簡體   English   中英

python多處理池並不總是使用所有工作者

[英]python multiprocessing Pool not always using all workers


問題:
當將1000個任務發送到apply_async時,它們在所有48個CPU上並行運行,但有時運行的CPU越來越少,直到只剩下一個CPU運行,並且只有當最后一個CPU完成其任務時,所有CPU才會繼續運行每個人都有一個新任務。 它不應該等待像這樣的任何“任務批處理”..

我的(簡化)代碼:

from multiprocessing import Pool
pool = Pool(47)
tasks = [pool.apply_async(json2features, (j,)) for j in jsons]
feats = [t.get() for t in tasks]

jsons = [...]是已加載到內存並解析為對象的大約1000個JSON的列表。
json2features(json)json2features(json)執行一些CPU繁重的工作,並返回一個數字數組。
此功能可能需要1秒到15分鍾才能運行,因此我使用啟發式排序jsons,希望最長的任務首先在列表中,因此首先啟動。

json2features函數還會在任務完成時以及花費的時間內打印。 它全部運行在一個擁有48個核心的ubuntu服務器上,就像我上面所說的那樣,使用全部47個核心,它開始很棒。 然后,當任務完成時,運行的核心越來越少,這聽起來完全沒問題,不是因為在最后一個核心完成之后(當我看到它打印到stdout時),所有CPU都開始在新任務上再次運行,這意味着這不是真正的清單結束。 它可能會再次執行相同的操作,然后再次執行列表的實際結束。

有時它只能使用一個核心5分鍾,當任務最終完成時,它會再次開始使用所有核心,處理新任務。 (所以它不會停留在某些IPC開銷上)

沒有重復的jsons,也沒有任何依賴關系(它們都是靜態的,新鮮的磁盤數據,沒有引用等等),也沒有json2features調用之間的任何依賴關系(沒有全局狀態或任何東西),除了它們使用相同的終端他們的印刷品。

我懷疑問題是工作人員在調用get結果之前不會被釋放,所以我嘗試了以下代碼:

from multiprocessing import Pool
pool = Pool(47)
tasks = [pool.apply_async(print, (i,)) for i in range(1000)]
# feats = [t.get() for t in tasks]

並且它會打印所有1000個數字,即使沒有調用get

我現在已經沒想到問題可能是什么了。
這真的是Pool的正常行為嗎?

非常感謝!

multiprocessing.Pool依賴於單個os.pipe將任務交付給worker。

通常在Unix ,默認管道大小范圍為4到64 Kb。 如果您提供的JSON大小很大,您可能會在任何給定的時間點堵塞管道。

這意味着,當其中一名工人忙於從管道中讀取大型JSON時,所有其他工作人員都會餓死。

通過IPC共享大數據通常是一種不好的做法,因為它會導致性能不佳。 多處理編程指南中甚至強調了這一點。

避免共享狀態

應盡可能避免在進程之間轉移大量數據。

不要在主進程中讀取JSON文件,只需向工作人員發送文件名,然后讓他們打開並閱讀內容。 您肯定會注意到性能的提高,因為您也在並發域中移動JSON加載階段。

請注意,結果也是如此。 單個os.pipe也用於將結果返回到主進程。 如果一個或多個工作人員阻塞了結果管道,那么您將獲得等待主管道排除它的所有進程。 應將大結果寫入文件。 然后,您可以利用主進程上的多線程快速回讀文件中的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM