我从单个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,内存消耗通过屋顶。我想通过重复使用进程槽来泄漏。
不确定过程中出了什么问题。
提前感谢您发现错误或明智的建议。
答案 0 :(得分:0)
不确定过程中出了什么问题。
即使达到maxProcess计数,您似乎也在创建与消息一样多的进程。
我在想通过重复使用流程插槽来泄漏。
无需自行管理流程。只需使用process pool:
# 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
class支持多种提交作业的方式:
如果邮件的到达速度足够快,可能最好收集其中几个(例如,一次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))
答案 1 :(得分:0)
总之,你的代码很奇怪: - )
它不是an 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
,只是这工作是boolean-ly-consideration this description from the documentation(此链接转到py2k docs但是py3k是相同的,而你的print
语句暗示你的代码仍然是py2k):
is_alive()
返回进程是否存活。
粗略地说,从
start()
方法返回到子进程终止之前,进程对象仍处于活动状态。
由于我们无法查看dosomething
的代码,因此很难说这些内容是否会终止。可能他们(通过退出),但如果他们没有,或者不是很快,我们可能会在这里遇到问题,我们只是放弃我们从外部循环中拉出队列的消息。
如果他们做终止,我们只需通过覆盖它从数组中删除进程引用:
processArray[i] = Process(...)
丢弃processArray [i]中的先前值。目前尚不清楚你是否已将其保存在其他任何地方,但如果你没有,那么Process实例将被丢弃,现在实际上不可能调用其join()
方法
某些Python数据结构倾向于在放弃时自行清理(例如,打开流刷新输出并根据需要关闭),但多进程代码似乎不会自动加入()其子进程。所以这可能是问题的根源,也可能是问题的来源。
最后,每当我们到达外部循环中的else
情况时,我们对任何活动进程都有相同的奇怪搜索 - 顺便说一下,它可以更清楚地写成:
if any(p.is_alive() for p in processArray):
只要我们不关心哪些特定的是活着的,哪些不是 - 如果没有人将自己报告为活着,我们会重置计数,但绝不会做任何事情变量processArray
,以便每个processArray[i]
仍然保存Process实例的标识。 (所以至少我们可以在每个上面调用join
,不包括因覆盖而丢失的任何内容。)
与使用Pool
及其multiprocess.Pool
和apply
方法相比,您最好不要自行构建自己的apply_async
。miraculixx's answer。< / p>