我正在使用Python的multiprocessing.Pool类在进程间分配任务。
简单的案例按预期工作:
from multiprocessing import Pool
def evaluate:
do_something()
pool = Pool(processes=N)
for task in tasks:
pool.apply_async(evaluate, (data,))
产生了N个进程,它们不断地完成我传递给apply_async的任务。现在,我有另一种情况,我有许多不同的非常复杂的对象,每个对象都需要进行计算量大的活动。我最初让每个对象在它完成工作时按需创建自己的多处理.Pool,但是我最终因为打开了太多文件而遇到了OSError,尽管我会假设这些池使用后会收集垃圾。
无论如何,我认为最好为这些复杂对象中的每一个共享同一个池进行计算:
from multiprocessing import Pool
def evaluate:
do_something()
pool = Pool(processes=N)
class ComplexClass:
def work:
for task in tasks:
self.pool.apply_async(evaluate, (data,))
objects = [ComplexClass() for i in range(50)]
for complex in objects:
complex.pool = pool
while True:
for complex in objects:
complex.work()
现在,当我在我的一台计算机上运行它(OS X,Python = 3.4)时,它的运行方式与预期一致。产生了N个进程,每个复杂对象在每个进程中分配它们的任务。但是,当我在另一台计算机上运行它(运行Ubuntu的Google Cloud实例,Python = 3.5)时,会产生大量进程(>> N),整个程序因争用而停止运行。
如果我查看游泳池以获取更多信息:
import random
random_object = random.sample(objects, 1)
print (random_object.pool.processes)
>>> N
一切看起来都很正确。但它显然不是。可能会发生什么想法?
更新
我添加了一些额外的日志记录。为简单起见,我将池大小设置为1。在池中,当任务完成时,我使用os.getpid()从多处理模块打印current_process(),以及任务的pid。结果是这样的:
<ForkProcess(ForkPoolWorker-1, started daemon)>, PID: 5122
<ForkProcess(ForkPoolWorker-1, started daemon)>, PID: 5122
<ForkProcess(ForkPoolWorker-1, started daemon)>, PID: 5122
<ForkProcess(ForkPoolWorker-1, started daemon)>, PID: 5122
...
再次,看看使用htop的实际活动,我看到许多进程(每个对象共享多处理池一个)都在消耗CPU周期,因为这种情况正在发生,导致操作系统争用太多,进展非常缓慢。 5122似乎是父进程。
答案 0 :(得分:1)
如果实现无限循环,则它将像无限循环一样运行。 您的示例(由于其他原因完全无效)...
while True:
for complex in objects:
complex.work()
即使上面的代码仅显示了一些摘要,但您一方面不能期望在Windows / MacOS和Linux上获得相同的结果。前者产生过程,后者派生它们。如果使用可能具有状态的全局变量,则在一种环境上开发而在另一种环境上运行时会遇到麻烦。
请确保不要在进程中使用全局statefull变量。只需明确地传递它们,或以其他方式摆脱它们。
编写具有最低要求的程序,使其具有__main__
。特别是,当您使用多处理时,您需要此。在该名称空间中实例化Pool。
答案 1 :(得分:0)
1)您的问题包含的代码与您运行的代码不同(相关代码的语法不正确,根本无法运行)。
2)多处理模块在错误处理/报告工作中发生的错误方面非常糟糕。
问题非常可能出现在您无法显示的代码中。您显示的代码(如果已修复)将永远工作并占用CPU,但它不会因太多打开的文件或进程而导致错误。