目錄
map
apply
map_async和apply_async
imap和imap_unordered
starmap和starmap_async
python多進程標准庫multiprocessing通過進程池啟動多進程有以下幾種方式,本文旨在說明這幾種方式的區別:map、apply、map_async、apply_async、imap、imap_unordered、starmap、starmap_async。
map函數簽名:map
(func, iterable[, chunksize])
從函數簽名來看,map會自動將func函數依次應用在iterable中的每個參數上,從而會產生多個並行的func任務,同時有多少個任務在並行取決於在創建進程池時指定了多少個進程。map的多個子任務中,一旦有一個出現了異常,那麼所有的結果將無法獲取,但是其他子任務會正常運行(如果chunksize不為1,那麼以chunk為單位,某個chunk出現異常,該chunk會立即停止,但其他chunk會正常運行,只是依然無法獲取結果)。
如果map函數設置了chunksize,那麼map會把iterable參數進行等分,每份的大小等於 chunksize,需要注意的是,每個chunk會分配給一個進程順序執行,這可能導致進程池中某個進程實際上已經處理完自己的chunk處於閒置狀態了,但是並不能獲取其他進程還未處理完的chunk中的任務,導致這些提早結束的進程處於閒置狀態,浪費資源。當然,如果不設置chunksize參數,那麼默認是對iterable中的參數逐個處理,即chunksize等於1,這樣一旦有進程處理完某個任務後,會立即獲取下一個參數繼續處理,不會處於閒置狀態;但是這樣的缺陷就是,如果iterable參數過長,會導致頻繁的給進程切換上下文,降低效率,而設定chunksize將參數一次傳給進程可以避免頻繁切換。
iterable參數過長還可能造成內存消耗過大,因為map會一次性把iterable對應的多個子任務得到的結果保存在一個list中,這樣內存中會保存一個很長的list,可能會過多消耗內存。這種情況下,可以使用下面的imap/imap_unordered,再結合chunksize參數,可以顯著提升效率。
apply函數簽名:apply
(func[, args[, kwds]])
apply只是將func函數作為一個任務添加到進程中並執行,args和kwds是可選的傳給func的位置參數和關鍵字參數,該函數每次只能運行一個任務,結束了之後才能運行下一個任務,因此,apply實際上並不能利用子進程進行多任務並行。
map_async函數簽名:map_async
(func, iterable[, chunksize[, callback[, error_callback]]])
apply_async函數簽名:apply_async
(func[, args[, kwds[, callback[, error_callback]]]])
相比於map和apply,這兩個函數不會阻塞主進程。如果在程序中,想要阻塞進行直至任務執行結束,那麼可以調用pool的join方法,該方法會阻塞子進程直至所有任務結束;要注意的是,在調用join方法之前,需要先調用pool的close方法,表示任務添加完畢,這樣join才被允許調用。
這兩個函數都會返回AsyncResult對象,AsyncResult對象的get函數可以獲取運行結果。對於map_async函數,AsyncResult對象的get函數得到的是一個包含了多個任務運行結果的列表,而且結果的順序和輸入的iterable順序一致。對於apply_async,其對應的AsyncResult的get函數返回的就是func函數返回的結果。
AsyncResult的get函數會阻塞主進程,直至子進程的任務全部執行完。即map_async(func,iterable).get()等效於map(func,iterable),apply_async(func,args).get()等效於apply(func,args)。
imap是map的lazy版本,即不會一次性的生成所有子任務的結果並存在一個list中返回,而是返回一個迭代器,等主進程主動迭代,再返回結果供進一步處理,而不是等所有子任務的結果全部生成後再處理,這樣可以大大減少內存使用;對於iterable較長的情況,結合chunksize的合理使用,其相比map可以顯著提升效率。
但是imap有一個問題是,迭代器返回的結果是保序的,即,盡管iterable參數中,比較靠後的參數對應的子任務已經完成可以返回結果供下一步處理,但是如果第一個參數對應的任務耗時較久,那麼主進程還是會繼續阻塞,無法先處理已經先生成的結果。該迭代器只會按順序的迭代,並且只有等到迭代到參數對應的子任務完成後,才會進行下一步,不然會繼續阻塞。
對於上述imap按順序迭代獲取結果帶來的潛在的內存消耗以及cpu資源浪費問題,可以通過imap_unordered解決。imap_unordered相比於imap,其不要求迭代器保序,只要某個子任務結束返回了結果,迭代器就會立即准備好供主進程獲取並進行下一步處理,而不會因為順序迭代的原因阻塞在某個進程上。
相比map和map_async,starmap和starmap_async唯一的區別就是要求iterable中的元素也是可迭代的,並將可迭代元素解包成多個位置參數傳給func。即如果iterable是[(1,2),(3,4)],那麼子任務分別是func(1,2)和func(3,4)。