使用Python多处理的高内存使用率
我已经看过几篇关于使用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
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个任务!