Python的多处理和内存

时间:2012-06-24 00:47:57

标签: python multiprocessing

我正在使用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。欢呼声。

2 个答案:

答案 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函数,该函数将使用信号量来控制一次可以执行的同时作业执行的总数(我假设为主进程/线程将增加信号量)。可以根据作业大小和可用内存计算信号量值。