ProcessPoolExecutor和ThreadPoolExecutor有什么区别?

ana*_*nya 3 python parallel-processing multithreading python-3.x python-3.5

我阅读了试图获得基本理解的文档,但它仅表明ProcessPoolExecutor可以避开Global Interpreter Lock我认为是锁定变量或函数的方式,从而使并行进程不会同时更新其值。

我要寻找的是何时使用ProcessPoolExecutor,何时使用ThreadPoolExecutor以及使用每种方法时应记住的事项!

小智 18

ProcessPool 用于 CPU 密集型任务,因此您可以从多个 CPU 中受益。

线程用于 io 绑定任务,因此您可以从 io 等待中受益。

  • 我真的很喜欢这个答案的简洁性。这个答案不足以单独满足我的需求(它没有解释原因,所以我不会只是使用它),但它确实帮助我理解了批准的答案,因为没有不确定的术语和有限的术语。 (5认同)

aba*_*ert 6

ProcessPoolExecutor 在您自己的子进程中运行每个工人。

ThreadPoolExecutor 在主进程的不同线程中运行每个工作程序。

全局解释器锁定(GIL)不仅锁定变量或函数,还锁定其他变量或函数。它锁定整个解释器。这意味着每个内置操作(包括)listodicts[3]['spam'] = eggs都自动是线程安全的。

但这也意味着,如果您的代码受CPU限制(也就是说,它花费时间进行计算,而不是例如等待网络响应),而不是将大部分时间都花在旨在释放GIL的外部库中(像NumPy),一次只能有一个线程拥有GIL。因此,如果您有4个线程,即使您有4个甚至16个内核,大多数情况下,其中3个将坐在那里等待GIL。因此,您的代码不会变得更快4倍,而是会变得更慢。

再次,对于受I / O约束的代码(例如,等待一堆服务器以响应您发出的一堆HTTP请求),线程就很好了。这仅是针对CPU绑定的代码的问题。

每个单独的子进程都有其自己的单独的GIL,因此,即使您的代码受CPU限制,这个问题也可以解决,使用4个子进程仍然可以使其运行速度几乎提高了4倍。

但是子进程不共享任何变量。通常,这是一件好事:将值的(副本)作为参数传递给函数,然后将值的(副本)返回,并且进程隔离保证您可以安全地进行此操作。但是有时(通常出于性能原因,有时还因为您传递了无法通过复制的对象pickle),这是不可接受的,因此您需要使用线程,或者在其中使用更复杂的显式共享数据包装器该multiprocessing模块。