Python线程池与进程池
前言前面我们已经将线程并发编程与进程并行编程全部摸了个透,其实我第一次学习他们的时候感觉非常困难甚至是吃力。因为概念实在是太多了,各种锁,数据共享同步,各种方法等等让人十分头痛。所以这边要告诉你一个好消息,前面的所有学习的知识点其实都是为本章知识点做铺垫,在学习了本章节的内容后关于如何使用多线程并发与多进程并行就采取本章节中介绍的方式即可。 这里要介绍一点与之前内容不同的地方,即如果使用队列进行由进程池创建的进程之间数据共享的话不管是 ?官方文档 执行器最早期的Python2中是没有线程池这一概念的,只有进程池。直到Python3的出现才引入了线程池,其实关于他们的使用都是非常简单,而且接口也是高度统一甚至说一模一样的。而线程池与进程池的作用即是为了让我们能够更加便捷的管理线程或进程。 我们先说一下,如果需要使用线程池或进程池,需要导入模块
这里介绍一下,关于线程池或者进程池创建出的线程与进程与我们使用 import threading def task(): ident = threading.get_ident() print(ident) # 销毁当前执行任务的线程 if __name__ == '__main__': for i in range(10): t1 = threading.Thread(target=task,) 领任务 t1.start() 等待CPU调度,而不是立即执行 # 执行 ==== 执行结果 ==== Ps:可以看到每个线程的id号都不一样,这也印证了图上说的。 """ 10392 12068 5708 13864 2604 7196 7324 9728 9664 472 """ threading from concurrent.futures import ThreadPoolExecutor 线程池执行器 结束任务,不销毁当前执行任务的线程,直到所有任务都执行完毕。 : pool = ThreadPoolExecutor(max_workers=2) 这里代表有2个线程可以领取任务 ): pool.submit(task) 执行器启动任务,将这些任务给2个人分配,也就是说task这个任务会被这2个线程不断的执行,直到执行完毕后这2个线程才会死亡 ==== 执行结果 ==== Ps:可以看到这里都让这2个线程把任务接了,内存开销相比于上面的要小。 7272 7272 7272 7272 11596 7272 11596 11596 11596 11596 """ 方法大全
?基本使用 其实关于执行器的使用,我们有两种方式,一种是依赖于 不依赖于 task(): print("执行了") 这里代表有2个线程可以领取任务 , 对于线程池来讲它是默认值是CPU核心数+4,对于进程池来讲最大开启的进程数是CPU核心数。 执行器启动任务,将这些任务给2个人分配,也就是说task这个任务会被这2个线程不断的执行,直到执行完毕后这2个线程才会死亡 执行了 执行了 执行了 执行了 执行了 执行了 执行了 执行了 执行了 执行了 """ 依赖于 ) 销毁 : with ThreadPoolExecutor(max_workers=2) as pool: 这里代表有2个线程可以领取任务 , 对于线程池来讲它是默认值是CPU核心数+4,对于进程池来讲最大开启的进程数是CPU核心数。 ): pool.submit(task) """ 期程对象方法大全
期程对象的作用我们可以看到,我们上面的函数并没有返回值,如果有返回值的话怎么办呢? return 玫瑰花" : with ThreadPoolExecutor(max_workers=2) as pool: res = pool.submit(task) print(res) <Future at 0x2539ea97850 state=finished returned str> 这个就是期程对象,可以看到他里面还有当前任务的执行状态。 finished = 执行完了的意思 print(res.result()) 通过该方法就可以拿到任务的返回结果 ==== 执行结果 ==== 执行了 <Future at 0x2539ea97850 state=finished returned str> 玫瑰花 """ 期程对象,也被称为未来对象,是一个非常重要的概念。这里可以记一笔,在 期程对象如何获取返回结果我们尝试着将它的任务数量增多,发现使用期程对象直接获取任务结果会导致阻塞,怎么解决? time task(x): 执行了,这是第%s个任务"%x) time.sleep(3) as pool: ): res = pool.submit(task,i) 每次获取结果的时候都是阻塞,怎么办?这个速率就变得非常的Low逼了。 执行了,这是第0个任务 玫瑰花 执行了,这是第1个任务 玫瑰花 执行了,这是第2个任务 玫瑰花 执行了,这是第3个任务 玫瑰花 执行了,这是第4个任务 玫瑰花 执行了,这是第5个任务 玫瑰花 执行了,这是第6个任务 玫瑰花 执行了,这是第7个任务 玫瑰花 执行了,这是第8个任务 玫瑰花 执行了,这是第9个任务 玫瑰花 """ 我这里有一个办法,可以值得尝试一下。就是执行器本身有个方法 : res_list = [] 用于存放所有期程对象 with ThreadPoolExecutor(max_workers=2 将期程对象放入列表 pool.shutdown(wait=True) 代表必须将所有子线程的任务跑完再继续向下执行主线程。 in res_list: (i.result()) """ 如果你觉得这种方法很赞,我只能送你两个字,太low了。我们注意执行器的 回调函数def callback(res): 必须有一个形参,来接收期程对象 print(res.result()) 打印结果,即task任务的返回结果 : with ThreadPoolExecutor(max_workers=2 <--- 增加回调函数,当期程对象中的任务处理状态完毕后将自动调用回调函数 ==== 执行结果 ==== # 异步提交牛逼不?只要任务返回了我们立马就可以获取到结果进行处理。 """ 扩展:进程池执行器任务数据共享 当我们使用进程池执行器启动多进程执行任务时,如果想用数据共享,单纯 multiprocessing import ProcessPoolExecutor 进程池执行器 task_1(q): q.put(放完了... task_2(q): (q.get()) 取到了: q = multiprocessing.Queue() with ProcessPoolExecutor(max_workers=2) as pool: pool.submit(task_1,q) pool.submit(task_2,q) ==== 执行结果 ==== # 阻塞住 """ """ ? 这个时候我们需要用到 from multiprocessing Manager Manager().Queue() with ProcessPoolExecutor(max_workers=2 ==== 执行结果 ==== # 成功 放完了... 玫瑰花 取到了 """ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |