Python標準庫11 多程式探索 (multiprocessing包)

ii_chengzi發表於2019-12-18

初步瞭解Python多程式之後,我們可以繼續探索multiprocessing包中更加高階的工具。這些工具可以讓我們更加便利地實現多程式。

 

程式池

程式池  (Process Pool)可以建立 多個程式。這些程式就像是隨時待命計程車兵,準備執行任務(程式)。一個程式池中可以容納多個待命計程車兵。

 

“三個程式的程式池”

 

 

比如下面的程式:


import
 multiprocessing as mul
def
 f(x):    
return x**2
pool = 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.cnblogs.com
www.qq.com

使用包含3個程式的程式池下載檔案中網站的首頁。(你可以使用subprocess呼叫wget或者curl等下載工具執行具體的下載任務)

 

共享資源

我們在 Python多程式初步已經提到,我們應該儘量避免多程式共享資源。多程式共享資源必然會帶來程式間相互競爭。而這種競爭又會造成race condition,我們的結果有可能被競爭的不確定性所影響。但如果需要,我們依然可以透過共享記憶體和Manager物件這麼做。

 

共享“資源”

共享記憶體

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物件代表的程式。我們在主程式的記憶體空間中建立共享的記憶體,也就是 ValueArray兩個物件。物件Value被設定成為雙精度數(d), 並初始化為0.0。而Array則類似於C中的陣列,有固定的型別(i, 也就是整數)。在Process程式中,我們修改了Value和Array物件。回到主程式,列印出結果,主程式也看到了兩個物件的改變,說明資源確實在兩個程式之間共享。

 

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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31543790/viewspace-2669166/,如需轉載,請註明出處,否則將追究法律責任。

相關文章