繁体   English   中英

使用Process的Python多处理:消耗大内存

[英]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支持几种提交作业的方式:

  • apply_async-一次发送一条消息
  • map_async-一次发送大量消息

如果消息到达的速度足够快,则最好收集其中的几个(每次一次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()方法没有明确承诺返回TrueFalse ,只是布尔型的工作),请从文档中考虑以下说明 (此链接转到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以及它的applyapply_async方法,可能会更好,就像miraculixx的answer一样

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM