[英]Python Multiprocessing using Process: Consuming Large Memory
我正在从单个python代码运行多个进程:
代码段:
while 1:
if sqsObject.msgCount() > 0:
ReadyMsg = sqsObject.readM2Q()
if ReadyMsg == 0:
continue
fileName = ReadyMsg['fileName']
dirName = ReadyMsg['dirName']
uuid = ReadyMsg['uid']
guid = ReadyMsg['guid']
callback = ReadyMsg['callbackurl']
# print ("Trigger Algorithm Process")
if(countProcess < maxProcess):
try:
retValue = Process(target=dosomething, args=(dirName, uuid,guid,callback))
processArray.append(retValue)
retValue.start()
countProcess = countProcess + 1
except:
print "Cannot Run Process"
else:
for i in range(len(processArray)):
if (processArray[i].is_alive() == True):
continue
else:
try:
#print 'Restart Process'
processArray[i] = Process(target=dosomething, args=(dirName,uuid,guid,callback))
processArray[i].start()
except:
print "Cannot Run Process"
else: # No more request to service
for i in range(len(processArray)):
if (processArray[i].is_alive() == True):
processRunning = 1
break
else:
continue
if processRunning == 0:
countProcess = 0
else:
processRunning = 0
在这里,我从队列中读取消息,并创建一个进程以对该消息运行算法。 我把maxProcess的上限。 因此,在达到maxProcess之后,我想通过检查is_alive()来重用那些尚未激活的processArray插槽。
对于较少的进程,此进程运行良好,但是对于大量的消息(例如100),内存消耗将通过屋顶。 我想我是通过重用进程插槽来泄漏的。
不确定过程中有什么问题。
预先感谢您发现错误或提供明智的建议。
不确定过程中有什么问题。
看来您正在创建的进程与消息一样多,即使达到maxProcess计数也是如此。
我想我是通过重用进程插槽来泄漏的。
无需自己管理流程。 只需使用一个进程池 :
# before your while loop starts
from multiprocessing import Pool
pool = Pool(processes=max_process)
while 1:
...
# instead of creating a new Process
res = pool.apply_async(dosomething,
args=(dirName,uuid,guid,callback))
# after the while loop has finished
# -- wait to finish
pool.close()
pool.join()
提交工作的方式
请注意, Pool
类支持几种提交作业的方式:
如果消息到达的速度足够快,则最好收集其中的几个(每次一次10或100,具体取决于实际完成的处理),然后使用map
一次向目标函数提交“迷你批处理”:
...
while True:
messages = []
# build mini-batch of messages
while len(messages) < batch_size:
... # get message
messages.append((dirName,uuid,guid,callback))
pool.map_async(dosomething, messages)
为了避免留下内存泄漏dosomething
你可以问池重新启动的过程已消费的消息的一些号码后:
max_tasks = 5 # some sensible number
Pool(max_processes, maxtasksperchild=max_tasks)
分发
如果使用此方法仍超出了内存容量,请考虑使用分布式方法,即添加更多计算机。 使用Celery会很简单,来自上面:
# tasks.py
@task
def dosomething(...):
... # same code as before
# driver.py
while True:
... # get messages as before
res = somefunc.apply_async(args=(dirName,uuid,guid,callback))
总之,您的代码很奇怪:-)
它不是mvce ,因此没有其他人可以对其进行测试,但是仅查看它,您就会在内部循环中拥有这个(略微简化的)结构:
if count < limit:
... start a new process, and increment count ...
else:
do things that can potentially start even more processes
(but never, ever, decrease count)
这充其量似乎是不明智的。
任何地方都没有流程实例的join()
调用。 (稍后,我们将回到外循环及其else
情况。)
让我们更仔细地看一下内部循环的else
案例代码:
for i in range(len(processArray)):
if (processArray[i].is_alive() == True):
撇开不必要的== True
测试(这是有点风险的,因为is_alive()
方法没有明确承诺返回True
和False
,只是布尔型的工作),请从文档中考虑以下说明 (此链接转到py2k文档,但py3k相同,并且您的print
语句暗示您的代码无论如何都是py2k):
is_alive()
返回该过程是否仍然存在。
大致来说,从
start()
方法返回到子进程终止之间,进程对象一直处于活动状态。
既然我们不能看到代码dosomething
,很难说这些东西是否永远终止。 它们可能会这样做(通过退出),但是如果它们不这样做或没有足够快,我们可能会在这里遇到问题,在这里我们只是在外循环中丢弃从队列中拉出的消息。
如果它们确实终止了,我们可以通过覆盖它来从数组中删除流程引用:
processArray[i] = Process(...)
processArray [i]中的先前值将被丢弃。 目前尚不清楚是否可以将其保存在其他任何地方,但是如果没有保存,则Process实例将被丢弃,现在实际上无法调用其join()
方法。
一些Python数据结构在被抛弃时倾向于清理自身(例如,打开的流刷新输出并根据需要关闭),但是多进程代码似乎并未自动join()其子级。 因此,这可能是问题的根源,也可能是问题的根源。
最后,每当我们在外循环中找到else
情况时,对于任何活动的过程,我们都会有相同的奇怪搜索-顺便说一句,可以更清楚地写成:
if any(p.is_alive() for p in processArray):
只要我们不关心哪些特定对象还活着,哪些不存在,并且如果没有人将自己报告为还活着,我们将重置计数,但永远不会对变量processArray
进行任何操作,以便每个processArray[i]
仍然拥有流程实例的标识。 (因此,至少我们可以对每一个调用join
,不包括因覆盖而丢失的任何内容。)
与其自己构建自己的Pool
,不如使用multiprocess.Pool
以及它的apply
和apply_async
方法,可能会更好,就像miraculixx的answer一样 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.