簡體   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