我正在使用multiprocessing.imap_unordered
对值列表执行计算:
def process_parallel(fnc, some_list):
pool = multiprocessing.Pool()
for result in pool.imap_unordered(fnc, some_list):
for x in result:
yield x
pool.terminate()
每次调用fnc
都会因设计而返回一个巨大的对象。我可以在RAM中存储这种对象的N个实例,其中N~cpu_count,但不多(不是数百)。
现在,使用此功能会占用太多内存。记忆完全花在主要过程中,而不是在工人身上。
imap_unordered
如何存储完成的结果?我的意思是工作人员已经返回但尚未传递给用户的结果。我认为这很聪明,只是根据需要“懒洋洋地”计算它们,但显然不是。
看起来因为我不能足够快地消耗process_parallel
的结果,所以池会在内部某处从fnc
排队这些巨大的对象,然后爆炸。有办法避免这种情况吗?以某种方式限制其内部队列?
我正在使用Python2.7。欢呼声。
答案 0 :(得分:11)
通过查看相应的源文件(python2.7/multiprocessing/pool.py
)可以看到,IMapUnorderedIterator使用collections.deque
实例来存储结果。如果有新项目,则会在迭代中添加和删除它。
正如你所建议的,如果主线程仍在处理对象时另一个巨大的对象进入,那么它们也会存储在内存中。
你可能会尝试这样的事情:
it = pool.imap_unordered(fnc, some_list)
for result in it:
it._cond.acquire()
for x in result:
yield x
it._cond.release()
这会导致task-result-receiver-thread在处理项目时被阻塞,如果它试图将下一个对象放入双端队列中。 因此,内存中的巨大对象不应超过两个。 如果这适用于您的情况,我不知道;)
答案 1 :(得分:2)
我能想到的最简单的解决方案是添加一个闭包来包装你的fnc
函数,该函数将使用信号量来控制一次可以执行的同时作业执行的总数(我假设为主进程/线程将增加信号量)。可以根据作业大小和可用内存计算信号量值。