1. 啟動多進程的方式
- os.fork 只支持Unix,不支持windows
- 使用multiprocessing模塊: 創(chuàng)建Process的實例,傳入任務執(zhí)行函數(shù)作為參數(shù)
- 使用multiprocessing模塊: 派生Process的子類,重寫run方法
- 使用進程池Pool
2. 啟動多進程注意
- multiprocessing是基于fork(),因為windows沒有fork()函數(shù)但是可以通過在
__main__中啟動子進程來規(guī)避 - multiprocessing創(chuàng)建子進程時會在子進程空間中復制一份主進程的代碼,全局變量在多個子進程之間不共享
- 多進程之間數(shù)據(jù)是隔離的
3. python守護進程
- 正常情況下,如果主進程代碼執(zhí)行完成,但是子進程還沒有執(zhí)行完成,則程序還不會退出,而是繼續(xù)等待子進程。
- 當要實現(xiàn)子進程要隨主進程結束而結束時就可以設置守護進程。
- 設置守護進程的方式是在start()之前設置
daemon = True - p.terminate() 是終止一個進程,該代碼執(zhí)行后進程不是立刻結束,CPU還有一個調(diào)度的過程此時用p.is_alive()檢查發(fā)現(xiàn)結果為True,time.sleep() 一秒后再用p.is_alive()檢查會發(fā)現(xiàn)結果為False
4. python多進程鎖
- Lock類與RLock類相同:由于進程之間隨機調(diào)度:某進程可能執(zhí)行n條后,CPU接著執(zhí)行其他進程。為了多個進程同時操作一個內(nèi)存中的資源時不產(chǎn)生混亂,我們使用鎖。
- Lock類與RLock類的區(qū)別:無論是Lock還是RLock,提供的方法都非常簡單,acquire和release。但是Lock和RLock的區(qū)別是什么呢?RLock允許在同一線程中被多次acquire。而Lock卻不允許這種情況。注意:如果使用RLock,那么acquire和release必須成對出現(xiàn),即調(diào)用了n次acquire,必須調(diào)用n次的release才能真正釋放所占用的鎖。
5. python多進程信號量-Semaphore
- 信號量Semaphore是一個計數(shù)器,控制對公共資源或者臨界區(qū)域的訪問量,信號量可以指定同時訪問資源或者進入臨界區(qū)域的進程數(shù)。每次有一個進程獲得信號量時,計數(shù)器-1,若計數(shù)器為0時,其他進程就停止訪問信號量,一直阻塞直到其他進程釋放信號量。
6.python多進程事件
- 多進程中的事件Event-進程之間的狀態(tài)標記通信,它是由進程設置的信號標志,如果信號標志為真,則其他進程等待直到信號解除
- Event對象實現(xiàn)了簡單的進程通信機制,它提供了設置信號,清除信號,等待等用于實現(xiàn)進程間通信的方法
- Event對象創(chuàng)建時默認信號設置為False。False時會在wait()處阻塞,True時不阻塞
7. python多進程之隊列
- IPC(Inter-Process Communication)進程之間通信
- 隊列先進先出
- Queue()實例化是可以傳一個參數(shù)代表隊列上限,如果不傳或傳負數(shù)都表示隊列沒有限制。
- 當隊列容量不夠時會阻塞
- Queue可以創(chuàng)建共享的進程隊列,Queue是多進程安全的隊列,可以使用Queue實現(xiàn)多進程之間的數(shù)據(jù)傳遞
8. python多進程之JoinableQueue
- JoinableQueue 與Queue一樣也是multiprocessing模塊中的一個類,也可以用于創(chuàng)建進程隊列。
- JoinableQueue 創(chuàng)建可連接的共享進程隊列,隊列允許隊列的消費者通知生產(chǎn)者,隊列數(shù)據(jù)已被成功處理完成。通知過程是使用共享的信號和條件變量來實現(xiàn)的。
9. python多進程之Pipe
- Pipe返回2個連接對象(conn1, conn2),代表管道的兩端,默認是雙向通信的,即conn1和conn2都可以收發(fā)消息。
- Pipe是數(shù)據(jù)不安全的,所以如果是多個進程之間同時收發(fā)消息時,需要自己加鎖以達到數(shù)據(jù)安全。
- 如果是生產(chǎn)者或消費者中都沒有使用管道的某個端點,就應將它關閉。這也說明了為何在生產(chǎn)者中關閉了管道的輸出端,在消費者中關閉管道的輸入端。如果忘記執(zhí)行這些步驟,程序可能在消費者中的recv()操作上掛起。
- 管道是由操作系統(tǒng)進行引用計數(shù)的,必須在所有進程中關閉管道后才能生成EOFError異常。因此,在生產(chǎn)者中關閉管道不會有任何效果,除非消費者也關閉了相同的管道端點
10. python多進程之Pool
- 在程序實際處理問題過程中,忙時會有成千上萬的任務需要被執(zhí)行,閑時可能只有零星任務。那么在成千上萬個任務需要被執(zhí)行的時候,我們就需要去創(chuàng)建成千上萬個進程么?
- 首先,創(chuàng)建進程需要消耗時間,銷毀進程也需要消耗時間。第二即便開啟了成千上萬的進程,操作系統(tǒng)也不能讓他們同時執(zhí)行,這樣反而會影響程序的效率。因此我們不能無限制的根據(jù)任務開啟或者結束進程。那么我們要怎么做呢?
- 這樣就引入了進程池,進程池是指定義一個進程池,在里面放上固定數(shù)量的進程,有需求來了,就拿進程池中的一個進程來處理任務,等到處理完畢,進程并不關閉,而是將進程再放回進程池中繼續(xù)等待任務。
- 如果有很多任務需要執(zhí)行,進程池中的進程數(shù)量不夠,任務就要等待之前的進程執(zhí)行任務完畢歸來,拿到空閑進程才能繼續(xù)執(zhí)行。也就是說,池中進程的數(shù)量是固定的,那么同一時間最多有固定數(shù)量的進程在運行。這樣不會增加操作系統(tǒng)的調(diào)度難度,還節(jié)省了開閉進程的時間,也一定程度上能夠實現(xiàn)并發(fā)效果。
11.python多進程之Manager
- Python中提供了強大的Manager類,專門用于實現(xiàn)多進程之間的數(shù)據(jù)共享;
- Manager類是數(shù)據(jù)不安全的;
- Mangaer類支持的類型非常多,如:value, Array, List, Dict, Queue, Lock等。
- Manager 類包含的常用方法和屬性與Multiprocessing中其他常用類的方法屬性一致。
12.python多進程之回調(diào)函數(shù)
- 需要回調(diào)函數(shù)的場景:進程池中任何一個任務一旦處理完了,就立即告知主進程:我好了額,你可以處理我的結果了。主進程則調(diào)用一個函數(shù)去處理該結果,該函數(shù)即回調(diào)函數(shù)
- 我們可以把耗時間(阻塞)的任務放到進程池中,然后指定回調(diào)函數(shù)(主進程負責執(zhí)行),這樣主進程在執(zhí)行回調(diào)函數(shù)時就省去了I/O的過程,直接拿到的是任務的結果。
- 子進程執(zhí)行返回的結果做為回調(diào)函數(shù)的參數(shù)傳入。
- 回調(diào)函數(shù)是在主進程中執(zhí)行的?;卣{(diào)函數(shù)適用于子進程數(shù)多且耗時時間長的場景。