在python中实现多进程的一个简单方法就是
from multiprocessing import Pool
def calculate(number):
return number
if __name__ == '__main__':
pool = Pool()
result = pool.map(calculate, range(4))
另一种基于期货的实施方式是
from concurrent.futures import ProcessPoolExecutor
def calculate(number):
return number
with ProcessPoolExecutor() as executor:
result = executor.map(calculate, range(4))
两种选择基本上都做了同样的事情,但一个显著的区别是,我们不必用通常的 if __name__ == '__main__'
条款。这是因为期货的实施照顾到了这一点,还是我们有其他原因?
更广义的说,这两者之间的区别是什么?multiprocessing
和 concurrent.futures
? 什么时候选择一种比另一种更合适?
EDIT:我最初的假设是,守 if __name__ == '__main__'
只有在多处理时才需要,这是错的。很显然,在windows系统上两种实现方式都需要这个防护,而在unix系统上则不需要。
实际上你应该使用 if __name__ == "__main__"
侍卫 ProcessPoolExecutor
,也是。它使用的是 multiprocessing.Process
以填充其 Pool
掩耳盗铃 multiprocessing.Pool
所以所有关于可拾取性(特别是在Windows上)等的注意事项都是一样的。
我相信 ProcessPoolExecutor
是为了最终取代 multiprocessing.Pool
根据 Jesse Noller的发言 (Python 核心贡献者),当被问及为什么 Python 有两个 API 时。
Brian和我需要在人们对API感到满意的时候,对我们打算进行的整合进行工作。我的最终目标是将除了基本的多处理.ProcessQueue之外的任何东西从MP中移除,并将其放入concurrent.*中,并为其支持线程后端。
目前来说。ProcessPoolExecutor
主要是在做与之完全相同的事情 multiprocessing.Pool
用一个更简单(更有限)的API。如果你能摆脱使用 ProcessPoolExecutor
,使用这个,因为我认为它更有可能在长期得到增强。请注意,你可以使用所有的助手,从 multiprocessing
与 ProcessPoolExecutor
譬如 Lock
, Queue
, Manager
等,所以需要这些并不是使用的理由。multiprocessing.Pool
.
但它们的API和行为有一些显著的不同。
如果一个进程在 ProcessPoolExecutor
戛然而止。a BrokenProcessPool
异常,中止任何等待池进行工作的调用,并阻止新工作的提交。如果同样的事情发生在一个 multiprocessing.Pool
它将默默地替换终止的进程,但该进程中正在进行的工作将永远不会完成,这很可能导致调用代码永远挂起等待工作完成。
如果你运行的是Python 3.6或更低版本,支持的是 initializer
initargs
缺少 ProcessPoolExecutor
. 这方面的支持在3.7中才被加入。).
3.7中没有支持。ProcessPoolExecutor
对于 maxtasksperchild
.
concurrent.futures
在 Python 2.7 中并不存在,除非您手动安装后传。
如果您运行的是 Python 3.5 以下的版本,根据 这个问题, multiprocessing.Pool.map
胜过 ProcessPoolExecutor.map
. 请注意,性能差异非常小 每个工作项目因此,你可能只会在你使用 map
在一个非常大的iterable上。性能差异的原因是 multiprocessing.Pool
会将传递过来的iterable批量映射成chunks,然后将chunks传递给worker进程,这样可以减少父进程和子进程之间的IPC开销。ProcessPoolExecutor
always (或者从 3.5 开始的默认情况下) 每次只从 iterable 中传递一个项目给子进程,由于增加了 IPC 开销,这可能会导致大的 iterable 性能更慢。好消息是这个问题在Python 3.5中得到了解决,因为Python 3.5中的 chunksize
关键字参数已被添加到 ProcessPoolExecutor.map
当你知道你要处理大的迭代物时,可以用它来指定一个更大的分块大小。 请看这个 虫子 获取更多信息。
if __name__ == '__main__':
只是意味着你在命令提示符下使用了 python <scriptname.py> [options]
而不是 import <scriptname>
在python shell中。
当你在命令提示符下调用脚本时,会在 __main__
方法被调用。在第二个块中,
with ProcessPoolExecutor() as executor:
result = executor.map(calculate, range(4))
无论它是由命令提示符调用的还是由shell导入的,块都会被执行。