作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
在初步瞭解Python多進程之後,我們可以繼續探索multiprocessing包中更加進階的工具。這些工具可以讓我們更加便利地實現多進程。
1. 進程池
之前我們使用Process建立進程的時候,每次建立一個進程。進程池 (Process Pool) 建立多個進程。這些進程就像是隨時待命計程車兵,準備執行任務(程式)。一個進程池中可以容納多個待命計程車兵。
“三個進程的進程池”
比如下面的程式:
import multiprocessing as muldef f(x): return x**2pool = mul.Pool(5)rel = pool.map(f,[1,2,3,4,5,6,7,8,9,10])
print(rel)
我們建立了一個容許5個進程的進程池 (Process Pool) 。Pool啟動並執行每個進程都執行f()函數。我們利用map()方法,將f()函數作用到表的每個元素上。這與built-in的map()函數類似,只是這裡用5個進程平行處理。如果進程運行結束後,還有需要處理的元素,那麼的進程會被用於重新運行f()函數。除了map()方法外,Pool還有下面的常用方法。
apply_async(func,args) 從進程池中取出一個進程執行func,args為func的參數。它將返回一個AsyncResult的對象,你可以對該對象調用get()方法以獲得結果。
close() 進程池不再建立新的進程
join() wait進程池中的全部進程。必須對Pool先調用close()方法才能join。
練習:
有下面一個檔案download.txt。
www.sina.com.cnwww.163.comwww.iciba.comwww.cnblogs.comwww.qq.comwww.douban.com
使用包含3個進程的進程池下載檔案中網站的首頁。(你可以使用subprocess調用wget或者curl等下載工具執行具體的下載任務)
2. 共用資源
我們在Python多進程初步已經提到,我們應該盡量避免多進程共用資源。多進程共用資源必然會帶來進程間相互競爭。而這種競爭又會造成race condition,我們的結果有可能被競爭的不確定性所影響。但如果需要,我們依然可以通過共用記憶體和Manager對象這麼做。
共用“資源”
1) 共用記憶體
在Linux處理序間通訊中,我們已經講述了共用記憶體(shared memory)的原理,這裡給出用Python實現的例子:
# modified from official documentationimport multiprocessingdef f(n, a): n.value = 3.14 a[0] = 5num = multiprocessing.Value('d', 0.0)arr = multiprocessing.Array('i', range(10))p = multiprocessing.Process(target=f, args=(num, arr))p.start()p.join()print num.valueprint arr[:]
這裡我們實際上只有主進程和Process對象代表的進程。我們在主進程的記憶體空間中建立共用的記憶體,也就是Value和Array兩個對象。對象Value被設定成為雙精確度數(d), 並初始化為0.0。而Array則類似於C中的數組,有固定的類型(i, 也就是整數)。在Process進程中,我們修改了Value和Array對象。回到主程式,列印出結果,主程式也看到了兩個對象的改變,說明資源確實在兩個進程之間共用。
2)Manager
Manager對象類似於伺服器與客戶之間的通訊 (server-client),與我們在Internet上的活動很類似。我們用一個進程作為伺服器,建立Manager來真正存放資源。其它的進程可以通過參數傳遞或者根據地址來訪問Manager,建立串連後,動作伺服器上的資源。在防火牆允許的情況下,我們完全可以將Manager運用於多電腦,從而模仿了一個真實的網路情境。下面的例子中,我們對Manager的使用類似於shared memory,但可以共用更豐富的物件類型。
import multiprocessingdef f(x, arr, l): x.value = 3.14 arr[0] = 5 l.append('Hello')server = multiprocessing.Manager()x = server.Value('d', 0.0)arr = server.Array('i', range(10))l = server.list()proc = multiprocessing.Process(target=f, args=(x, arr, l))proc.start()proc.join()print(x.value)print(arr)print(l)
Manager利用list()方法提供了表的共用方式。實際上你可以利用dict()來共用詞典,Lock()來共用threading.Lock(注意,我們共用的是threading.Lock,而不是進程的mutiprocessing.Lock。後者本身已經實現了進程共用)等。 這樣Manager就允許我們共用更多樣的對象。
我們在這裡不深入講解Manager在遠程情況下的應用。有機會的話,會在網路應用中進一步探索。
總結
Pool
Shared memory, Manager