from concurrent.futures import ProcessPoolExecutor
def pool_factorizer_map(nums, nprocs):
# Let the executor divide the work among processes by using 'map'.
with ProcessPoolExecutor(max_workers=nprocs) as executor:
return {num:factors for num, factors in
zip(nums,
executor.map(factorize_naive, nums))}
这里使用multiprocessing完全相同:
import multiprocessing as mp
def mp_factorizer_map(nums, nprocs):
with mp.Pool(nprocs) as pool:
return {num:factors for num, factors in
zip(nums,
pool.map(factorize_naive, nums))}
我不会把
concurrent.futures
称为更“高级”—它是一个更简单的接口,无论您是使用多线程还是多进程作为底层并行化技巧,它的工作原理都非常相同。所以,就像几乎所有“简单界面”的例子一样,这也涉及到很多相同的权衡:它的学习曲线较浅,很大程度上是因为学习的可用性要少得多;但是,因为它提供的选项较少,它最终可能会以丰富界面不会有的方式让你失望
就CPU限制的任务而言,这是太少的指定,说不上有多大意义。对于CPython下的CPU绑定任务,需要多个进程而不是多个线程才能有任何加速的机会。但是,你的速度提升了多少(如果有的话)取决于你的硬件、操作系统的细节,尤其是你的特定任务需要多少进程间通信。实际上,所有进程间并行化的技巧都依赖于相同的操作系统原语——用于获取这些原语的高级API并不是底线速度的主要因素。
编辑:示例
这是您引用的文章中显示的最后一个代码,但我要添加一个import语句以使其工作:
这里使用
multiprocessing
完全相同:注意,Python 3.3中添加了使用
multiprocessing.Pool
对象作为上下文管理器的功能。哪一个比较容易用?LOL;-)它们基本上是一样的。
一个不同之处是
Pool
支持许多不同的做事方式,直到你在学习曲线上爬了很高的一段路,你可能才意识到这有多么容易。同样,所有这些不同的方式都是一种优势和劣势。它们是一种力量,因为在某些情况下可能需要灵活性。它们是一个弱点,因为“最好只有一个显而易见的方法”。一个完全(如果可能的话)依赖于
concurrent.futures
的项目可能在长期内更容易维护,因为在如何使用它的极简API方面缺乏无端的新颖性。相关问题 更多 >
编程相关推荐