【发布时间】:2014-02-24 10:58:55
【问题描述】:
我看过几篇关于使用 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 |
+---------------+----------------------+----------------------+
在上表中,我尝试更改任务数并观察在所有计算结束时和join-ing pool 之前消耗的内存。 'del' 和 'without del' 选项分别是我是否取消注释或注释 calculate(num) 函数内的 del l 行。计算前内存消耗在4400左右。
- 看起来手动清除列表会降低工作进程的内存使用率。我认为垃圾收集器会处理这个问题。有没有办法强制垃圾回收?
- 令人费解的是,随着任务数量的增加,两种情况下的内存使用量都在不断增长。有没有办法限制内存使用?
我有一个基于此示例的流程,旨在长期运行。我观察到这个工作进程在通宵运行后占用了大量内存(~4GB)。执行join 来释放内存不是一种选择,我正在尝试找出没有join-ing 的方法。
这似乎有点神秘。有没有人遇到过类似的事情?我该如何解决这个问题?
【问题讨论】:
-
似乎
del在这个测试用例中是多余的,因为l在函数返回后被垃圾回收。内存使用量的增加可能源于[num*num for num in range(num)],因为您将i传递为num,而i随着num_task的增加而增加。 -
感谢您的评论。我希望在所有任务完成后,子进程的内存消耗会恢复到它开始时的状态(~4400)。
-
也许这个例子不足以解决你真正的问题。在您的实际过程中,您可以考虑使用生成器而不是列表。另外,
gc.collect()可能会转到handy。 -
我的真实应用程序有更复杂的对象,而不是列表。我试图用示例代码来模拟我的问题。我将与
gc一起玩,看看是否有帮助。你有一个关于正确使用gc来释放内存的简单例子吗?谢谢! -
我用 gc 尝试了这个示例代码,但它没有帮助:( 但是,我对其进行了一些更改。我没有创建一个可变大小的新列表,而是使用`range 创建一个新列表(1000000)
. It took about 20MB. Afterdel l, python does no immediate gc. And explicitgc.collect()` 在函数calculate中确实有帮助。gc.collect的用法很简单,只需将其添加到子进程的末尾即可。但这会减慢您的进程很多,有条件地做手动gc。
标签: python performance memory multiprocessing