最后更新于
最后更新于
进程池创建时, 会克隆出一个Python解释器, 在Linux
上还会克隆原解释器中所有的程序状态, 在Windows
中不会包含运行状态.
另外, 如果将多线程和多进程结合在一起使用, 需要在创建任何线程之前, 优先创建并加载进程池.
有两种方法创建进程池.
进程池的使用方法如下:
注意:
使用apply_async或apply方法向子进程中添加任务, 使用这两种方法添加任务之后, 会立即在子进程中启动运行. 两者的区别在于前者是非阻塞的, 后者是阻塞的, 即使用apply
方法添加后, 需要等待这个任务执行完毕, 主进程才能继续执行.
上述代码的执行结果为:
如果上述代码的apply_async
方法改为apply
方法, 执行的结果就是:
close方法的作用是关闭进程池, 进程池不再接受新的任务, join方法的作用是阻塞父进程. 因此在调用阻塞方法时, 需要先调用进程池的close方法, 然后再调用join
方法进行阻塞.
terminate()方法才是真正的关闭进程池的方法, 结束所有工作子进程, 不再处理未完成的任务.
为了拿到任务的执行结果, 可以将apply_async
方法的返回结果进行收集:
```python
coding: utf-8
import time import multiprocessing
def func(msg): print("msg:", msg) time.sleep(3) print("end")
if name == "main": pool = multiprocessing.Pool(processes=3) results = [] for i in range(4): msg = "hello %d" % (i,) results.append(pool.apply_async(func, (msg,)))
msg: hello 0 msg: hello 1 msg: hello 2 end msg: hello 3 end end end
```
将apply_async
返回的对象收集起来, 如上面代码使用列表来收集
apply_async
返回的对象是multiprocessing.pool.ApplyResult
对象, 使用该对象的get()
方法得到任务函数返回的结果, 如果进程还没有执行完, get()
方法将会产生阻塞.
如同ThreadPoolExecutor
的使用方法, 用submit
或者map
方法提交任务.
ProcessPoolExecutor
对于每一个提交的任务, 都会创建一个Future
对象, 里面会装在很多内容, 如最后运行的结果. 但multiprocessing.Pool
就不会有这一步, 如果使用它的map
方法进行提交, Pool
对象会批量地提交任务, 然后直接就把结果返回, 不会产生额外的开销.
因此:
在大批量任务的应用场景下, 使用multiprocessing.Pool
进行多进程是更好的选择.
当任务执行的时间较长时, 使用ProcessPoolExecutor
带来的Futures
更好.
如果需要在处理完毕后执行callback
, 就只能使用ProcessPoolExecutor
了, 因为Pool
没有callback
的方法, 只能手动实现.
在中有一个关于两者之间速度的问题. 在处理较多任务的时候, ProcessPoolExecutor
方法会慢很多, 这主要是因为: