使用Python多处理的高内存使用率

使用Python多处理的高内存使用率,python,performance,memory,multiprocessing,Python,Performance,Memory,Multiprocessing,我已经看过几篇关于使用Python多处理模块的内存使用的文章。然而,这些问题似乎并没有回答我这里的问题。我发布我的分析,希望有人能帮助我 问题 我使用多进程并行执行任务,我注意到工作进程的内存消耗无限增长。我有一个小的独立示例,它应该复制我注意到的内容 import multiprocessing as mp import time def calculate(num): l = [num*num for num in range(num)] s = sum(l) de

我已经看过几篇关于使用Python多处理模块的内存使用的文章。然而,这些问题似乎并没有回答我这里的问题。我发布我的分析,希望有人能帮助我

问题 我使用多进程并行执行任务,我注意到工作进程的内存消耗无限增长。我有一个小的独立示例,它应该复制我注意到的内容

import multiprocessing as mp
import time

def calculate(num):
    l = [num*num for num in range(num)]
    s = sum(l)
    del l       # delete lists as an  option
    return s

if __name__ == "__main__":
    pool = mp.Pool(processes=2)
    time.sleep(5)
    print "launching calculation"
    num_tasks = 1000
    tasks =  [pool.apply_async(calculate,(i,)) for i in range(num_tasks)]
    for f in tasks:    
        print f.get(5)
    print "calculation finished"
    time.sleep(10)
    print "closing  pool"
    pool.close()
    print "closed pool"
    print "joining pool"
    pool.join()
    print "joined pool"
    time.sleep(5)
系统 我正在运行Windows,我使用任务管理器监视内存使用情况。我正在运行Python 2.7.6

观察 下面我总结了2个工作进程的内存消耗

+---------------+----------------------+----------------------+
|  num_tasks    |  memory with del     | memory without del   |
|               | proc_1   | proc_2    | proc_1   | proc_2    |
+---------------+----------------------+----------------------+
| 1000          | 4884     | 4694      | 4892     | 4952      |
| 5000          | 5588     | 5596      | 6140     | 6268      |
| 10000         | 6528     | 6580      | 6640     | 6644      |
+---------------+----------------------+----------------------+
在上表中,我尝试更改任务的数量,并观察在所有计算结束时以及加入
池之前所消耗的内存。“del”和“without del”选项分别是我是取消注释还是注释
calculate(num)
函数中的
dell
行。计算前,内存消耗约为4400

  • 看起来手动清除列表会降低工作进程的内存使用率。我以为垃圾收集器会处理好的。有没有办法强制垃圾收集
  • 令人费解的是,随着任务数量的增加,这两种情况下的内存使用量都在不断增长。有没有办法限制内存使用
  • 我有一个基于此示例的流程,它旨在长期运行。我观察到,这个工作进程在一夜之间运行后正在占用大量内存(~4GB)。执行
    join
    来释放内存不是一个选项,我正在试图找到一种不使用
    join
    -ing的方法


    这似乎有点神秘。有人遇到过类似的情况吗?如何解决此问题?

    我做了大量研究,但无法找到解决问题的方法。但有一个不错的解决方案,可以以很小的成本防止内存崩溃,特别是在服务器端长时间运行的代码上

    解决方案本质上是在固定数量的任务之后重新启动单个工作进程。python中的
    Pool
    类将
    maxstasksperchild
    作为参数。您可以指定
    maxstasksperchild=1000
    ,从而限制在每个子进程上运行1000个任务。到达
    maxstasksparchild
    编号后,池刷新其子进程。对最大任务使用一个谨慎的数字,可以平衡消耗的最大内存和重启后端进程的启动成本。
    的构造如下:

    pool = mp.Pool(processes=2,maxtasksperchild=1000)
    
    我把我的完整解决方案放在这里,以便对其他人有用

    import multiprocessing as mp
    import time
    
    def calculate(num):
        l = [num*num for num in range(num)]
        s = sum(l)
        del l       # delete lists as an  option
        return s
    
    if __name__ == "__main__":
    
        # fix is in the following line #
        pool = mp.Pool(processes=2,maxtasksperchild=1000)
    
        time.sleep(5)
        print "launching calculation"
        num_tasks = 1000
        tasks =  [pool.apply_async(calculate,(i,)) for i in range(num_tasks)]
        for f in tasks:    
            print f.get(5)
        print "calculation finished"
        time.sleep(10)
        print "closing  pool"
        pool.close()
        print "closed pool"
        print "joining pool"
        pool.join()
        print "joined pool"
        time.sleep(5)
    

    这里一个潜在的问题是,结果可能以任何顺序返回,但因为您是按顺序读取的,所以它必须将从进程返回的所有结果存储在内存中。num_tasks越多,它在内存中存储的结果就越多,等待forf-in tasks循环处理结果

    在最坏的情况下,结果的计算顺序正好相反。在这种情况下,在for f In tasks循环开始处理任何内容之前,所有结果都必须由多处理模块保存在内存中

    在这种情况下,它们使用的内存量似乎比我预期的要高(比仅存储calculate()函数返回的1000-10000个数字所需的内存量要多),但可能存储的每个worker结果都有很高的恒定开销


    您是否尝试过指定回调参数以应用异步,这样您可以在结果完成时立即处理结果,或者使用imap无序,这样它可以在结果准备好后立即返回结果?

    在这个测试用例中,
    del
    似乎是多余的,因为
    l
    在函数返回后被垃圾收集。内存使用量的增加可能源于
    [num*num for num in range(num)]
    ,因为您将
    i
    作为
    num
    传递,并且
    i
    随着
    num\u任务的增加而增加。谢谢您的评论。我希望在所有任务完成后,子进程的内存消耗会恢复到最初的状态(~4400)。也许这个示例不足以解决您的实际问题。在实际过程中,可以考虑使用生成器而不是列表。另外,
    gc.collect()
    可能会用到。我真正的应用程序有更复杂的对象,而不是列表。我试图用示例代码来模拟我的问题。我将玩
    gc
    ,看看这是否有帮助。您是否有一个正确使用
    gc
    释放内存的快速示例。谢谢我用gc尝试了这个示例代码,但没有任何帮助:(不过,我对它做了一点修改。我没有创建一个大小可变的新列表,而是创建了一个带有“range(1000000)
    的新列表。它花费了大约20MB。在
    dell
    之后,python不会立即执行gc。而显式的
    gc.collect()`在函数中,
    calculate
    确实有帮助。
    gc.collect
    的用法很简单,只需将其添加到子流程的末尾即可。但这会大大降低您的流程速度,有条件地手动执行gc。+1因为maxtasksperschild是解决此问题的方法。我已经多次处理此问题,发现很难找到解决方案注意:当我不使用Pool,但使用proc=Process(target=func,args=args)时,有没有办法避免这个问题?我已经为这个问题挣扎了很长一段时间,它让我省去了一个巨大的头痛!+1!谢谢你的帖子。我遇到了一个类似的问题,并且尝试了许多其他的修复方法,比如在子进程函数中使用gc等,但都不起作用,但这也达到了预期效果,内存泄漏最终消失了!多少钱RAM是1000个任务!