来自concurrent.futures的ProcessPoolExecutor比multiprocessing.Pool慢

ast*_*nlu 34 python concurrency future multiprocessing concurrent.futures

我是用新的闪亮试验concurrent.futures在Python 3.2中引入模块,和我注意到,几乎相同的代码,使用泳池从concurrent.futures的方式比使用慢multiprocessing.Pool.

这是使用多处理的版本:

def hard_work(n):
    # Real hard work here
    pass

if __name__ == '__main__':
    from multiprocessing import Pool, cpu_count

    try:
        workers = cpu_count()
    except NotImplementedError:
        workers = 1
    pool = Pool(processes=workers)
    result = pool.map(hard_work, range(100, 1000000))
Run Code Online (Sandbox Code Playgroud)

这是使用concurrent.futures:

def hard_work(n):
    # Real hard work here
    pass

if __name__ == '__main__':
    from concurrent.futures import ProcessPoolExecutor, wait
    from multiprocessing import cpu_count
    try:
        workers = cpu_count()
    except NotImplementedError:
        workers = 1
    pool = ProcessPoolExecutor(max_workers=workers)
    result = pool.map(hard_work, range(100, 1000000))
Run Code Online (Sandbox Code Playgroud)

使用本Eli Bendersky文章中的天真因子分解函数,这些是我的计算机上的结果(i7,64位,Arch Linux):

[juanlu@nebulae]?[~/Development/Python/test]
?[10:31:10] $ time python pool_multiprocessing.py 

real    0m10.330s
user    1m13.430s
sys 0m0.260s
[juanlu@nebulae]?[~/Development/Python/test]
?[10:31:29] $ time python pool_futures.py 

real    4m3.939s
user    6m33.297s
sys 0m54.853s
Run Code Online (Sandbox Code Playgroud)

我不能用Python分析器来分析这些,因为我得到了pickle错误.有任何想法吗?

mat*_*ata 51

使用mapfrom时concurrent.futures,iterable中的每个元素单独提交给执行程序,后者Future为每个调用创建一个对象.然后它返回一个迭代器,它产生期货返回的结果.
Future对象是相当重量级的,他们做了很多工作来允许他们提供的所有功能(如回调,取消能力,检查状态......).

与此相比,multiprocessing.Pool开销要少得多.它批量提交作业(减少IPC开销),并直接使用函数返回的结果.对于大批量的工作,多处理绝对是更好的选择.

如果您希望在开销不重要的长期运行工作中进行总结,那么期货很有用,您希望通过回调或不时检查来查看它们是否已完成或能够单独取消执行.

个人说明:

我真的不能想到使用多少理由Executor.map- 它没有给你任何期货的功能 - 除了指定超时的能力.如果您只对结果感兴趣,最好使用其中一个multiprocessing.Pool地图功能.

  • 对于它的价值,在Python 3.5中,`ProcessPoolExecutor.map`将接受一个`chunksize`关键字参数,这将在一定程度上缓解IPC开销问题.有关详细信息,请参阅此[bug](http://bugs.python.org/issue11271). (9认同)
  • 我更喜欢 `ProcessPoolExecutor.map()` 因为 [这个错误](/sf/answers/1742649821/) 在 `mp.Pool.map()` 中 (3认同)