[英]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.