但在使用這些共享API的時候,咱們要注意下面幾點:
1)在UNIX平臺上,當某個進程終結以後。該進程需要被其父進程調用wait,不然進程成爲殭屍進程(Zombie)。python
因此。有必要對每個Process對象調用join()方法 (實際上等同於wait)。對於多線程來講,由於僅僅有一個進程。因此不存在此必要性。
2)multiprocessing提供了threading包中沒有的IPC(比方Pipe和Queue),效率上更高。shell
應優先考慮Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因爲它們佔領的不是用戶進程的資源)。
3)多進程應該避免共享資源。數組
在多線程中,咱們可以比較easy地共享資源,比方使用全局變量或者傳遞參數。
在多進程狀況下。由於每個進程有本身獨立的內存空間。以上方法並不合適。此時咱們可以經過共享內存和Manager的方法來共享資源。
但這樣作提升了程序的複雜度,並因爲同步的需要而減小了程序的效率。Process.PID中保存有PID,假設進程尚未start()。則PID爲None。服務器
咱們可以從如下的程序中看到Thread對象和Process對象在使用上的類似性與結果上的不一樣。各個線程和進程都作一件事:打印PID。
但問題是,所有的任務在打印的時候都會向同一個標準輸出(stdout)輸出。這樣輸出的字符會混合在一塊兒,沒法閱讀。
使用Lock同步,在一個任務輸出完畢以後,再贊成還有一個任務輸出,可以避免多個任務同一時候向終端輸出。網絡
# Similarity and difference of multi thread vs. multi process import os import threading import multiprocessing # worker function def worker(sign, lock): lock.acquire() print(sign, os.getpid()) lock.release() # Main print('Main:',os.getpid()) # Multi-thread record = [] lock = threading.Lock() for i in range(5): thread = threading.Thread(target=worker,args=('thread',lock)) thread.start() record.append(thread) for thread in record: thread.join() # Multi-process record = [] lock = multiprocessing.Lock() for i in range(5): process = multiprocessing.Process(target=worker,args=('process',lock)) process.start() record.append(process) for process in record: process.join()
咱們經過mutiprocessing.Pipe(duplex=False)建立單向管道 (默以爲雙向)。
一個進程從PIPE一端輸入對象,而後被PIPE還有一端的進程接收,單向管道僅僅贊成管道一端的進程輸入,而雙向管道則贊成從兩端輸入。多線程
如下的程序展現了Pipe的使用:
app
# Multiprocessing with Pipe import multiprocessing as mul def proc1(pipe): pipe.send('hello') print('proc1 rec:',pipe.recv()) def proc2(pipe): print('proc2 rec:',pipe.recv()) pipe.send('hello, too') # Build a pipe pipe = mul.Pipe() # Pass an end of the pipe to process 1 p1 = mul.Process(target=proc1, args=(pipe[0],)) # Pass the other end of the pipe to process 2 p2 = mul.Process(target=proc2, args=(pipe[1],)) p1.start() p2.start() p1.join() p2.join()
import os import multiprocessing import time #================== # input worker def inputQ(queue): info = str(os.getpid()) + '(put):' + str(time.time()) queue.put(info) # output worker def outputQ(queue,lock): info = queue.get() lock.acquire() print (str(os.getpid()) + '(get):' + info) lock.release() #=================== # Main record1 = [] # store input processes record2 = [] # store output processes lock = multiprocessing.Lock() # To prevent messy print queue = multiprocessing.Queue(3) # input processes for i in range(10): process = multiprocessing.Process(target=inputQ,args=(queue,)) process.start() record1.append(process) # output processes for i in range(10): process = multiprocessing.Process(target=outputQ,args=(queue,lock)) process.start() record2.append(process) for p in record1: p.join() queue.close() # No more object will come, close the queue for p in record2: p.join()
一個進程池中可以容納多個待命的士兵。async
比方如下的程序:
函數
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)
1)apply_async(func,args)從進程池中取出一個進程運行func。args爲func的參數。
它將返回一個AsyncResult的對象。你可以對該對象調用get()方法以得到結果。ui
2)close()進程池再也不建立新的進程
3)join()wait進程池中的全部進程。
必須對Pool先調用close()方法才幹join。
import multiprocessing def f(n, a): n.value = 3.14 a[0] = 5 num = 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.value print arr[:]
咱們用一個進程做爲server,創建Manager來真正存放資源。其餘的進程可以經過參數傳遞或者依據地址來訪問Manager,創建鏈接後。操做server上的資源。
在防火牆贊成的狀況下,咱們全然可以將Manager運用於多計算機。從而模仿了一個真實的網絡情境。
如下的樣例中,咱們對Manager的使用相似於shared memory。但可以共享更豐富的對象類型。
import multiprocessing def 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就贊成咱們共享不少其它樣的對象。