我已经看过几篇关于使用Python Multiprocessing模块的内存使用情况的帖子。然而问题似乎没有回答我在这里遇到的问题。我发布我的分析,希望有人可以帮助我。
我正在使用多处理来并行执行任务,我注意到工作进程的内存消耗无限增长。我有一个小的独立示例,应该复制我注意到的内容。
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
pool
之前消耗的内存。 'del'和'without del'选项分别是我对del l
函数内的calculate(num)
行取消评论或评论。在计算之前,内存消耗大约是4400。
我有一个基于这个例子的过程,并且意味着长期运行。我观察到这个工作进程在一夜之间运行后会占用大量内存(~4GB)。执行join
释放内存不是一种选择,我试图找到一种没有join
的方法。
这看起来有点神秘。有没有人遇到类似的东西?我该如何解决这个问题?
答案 0 :(得分:59)
我做了很多研究,但无法找到解决问题的解决方案。但是有一个不错的工作方法可以以很小的代价防止内存井喷,尤其是在服务器端长时间运行的代码上。
解决方案主要是在执行固定数量的任务后重新启动单个工作进程。 python中的Pool
类以maxtasksperchild
为参数。您可以指定maxtasksperchild=1000
,从而限制在每个子进程上运行1000个任务。达到maxtasksperchild
后,池会刷新其子进程。使用谨慎的数字来执行最大任务,可以平衡消耗的最大内存,以及与重新启动后端进程相关的启动成本。 Pool
构造完成如下:
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)
答案 1 :(得分:1)
这里的一个潜在问题是结果可能以任何顺序返回,但是由于您按顺序读取它们,因此必须将所有从进程返回的结果存储在内存中。 num_tasks 越高,它可能必须存储在内存中的结果越多,等待您的 for任务中的f 循环处理结果。
在最坏的情况下,结果以完全相反的顺序计算。在这种情况下,必须先将所有结果保存在内存中的多处理模块中,然后任务的 for 循环才会开始处理任何内容。
虽然它们使用的内存量似乎比我在这种情况下的预期要高(存储的calculate()函数返回的1000-10000个数字要多于此数量),但是可能存储的每个工作人员结果的开销总是很高。
您是否尝试为 apply_async 指定 callback 参数,以便您可以在完成结果后立即处理结果,也可以使用 imap_unordered ,这样可以在准备好结果后立即将结果给您?