高级编程技巧 学习笔记
一、进程池
1.1、为什么要用进程池
当需要创建的子进程数量不多时,可以直接利用 multiprocessing
中的 Process
动态生成多个进程,但是如果是上百甚至上千个目标,手动的去创建的进程的工作量巨大,此时就可以用到 multiprocessing
模块提供的 Pool
方法。
初始化 Pool 时,可以指定一个最大进程数,当有新的请求提交到 Pool 中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求,但是如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
1.2、代码实现
from multiprocessing import Pool
import os, time, random
def worker(msg):
t_start = time.time()
print('%s开始执行,进程号为%d' % (msg, os.getpid()))
time.sleep(random.random() * 2)
t_stop = time.time()
print(f"\n{msg}执行完成,耗时%0.2f" % (t_stop - t_start))
def demo():
pass
if __name__ == '__main__':
po = Pool(4) # 定义一个进程池 3个进程
for i in range(0, 10):
# 向进程池添加一个请求, 每个请求会占用一个进程
po.apply_async(worker, (i,))
print("--start--")
# 关闭进程池 不在接收新的请求
po.close()
# 此时想要添加新请求会报错
# po.apply_async(demo)
# 等待子进程执行完成
po.join()
print("--end--")
二、进程池间的进程通信
2.1、Queue() 实现进程池间的进程通信
import multiprocessing
def demo1(q):
q.put('a')
def demo2(q):
data = q.get()
print(data)
if __name__ == '__main__':
# q = Queue() # 普通队列, 不能实现进程之间的通信
# q = multiprocessing.Queue() # 实现进程之间的通信
q = multiprocessing.Manager().Queue() # 实现进程池之间的通信
po = multiprocessing.Pool(2)
po.apply_async(demo1, args=(q,))
po.apply_async(demo2, args=(q,))
po.close()
po.join()
2.3、Queue() 间的区别
到这里为止,已经知道了三个 Queue(),它们相似但作用却不尽相同。
-
Queue() —— 通过
" from queue import Queue "
导入: 普通队列,不能实现进程之间的通信 -
multiprocessing.Queue() —— 通过
" import multiprocessing "
导入: 实现进程之间的通信 -
multiprocessing.Manager().Queue() —— 通过
" import multiprocessing "
导入: 实现进程池之间的通信