1. 多進程
程序:program是一個指令的集合
進程:process,正在執(zhí)行中的程序,是一個靜態(tài)的概念
1) 進程是程序的一次靜態(tài)執(zhí)行過程,占用特定的地址空間
2) 每個進程都是獨立的,由3部分組成cpu,data,code
3) 缺點:內(nèi)存的浪費,cpu的負擔
4) 數(shù)據(jù)區(qū)、代碼區(qū)、堆、棧
操作系統(tǒng)輪流讓各個任務交替執(zhí)行,由于CPU的執(zhí)行速度實在是太快了,我們感覺就像所有任務都在同時執(zhí)行一樣
真正的并行執(zhí)行多任務只能在多核心CPU上實現(xiàn),但是,由于任務數(shù)據(jù)遠遠多于CPU的核心數(shù)量,所以,操作系統(tǒng)也會自動把很多任務輪流調(diào)度到每個核心上執(zhí)行
在unix/linux操作系統(tǒng)中,提供了一個fork()系統(tǒng)函數(shù),它非常特殊
1) 普通的函數(shù)調(diào)用,調(diào)用一次,返回一次,但是fork()調(diào)用一次,返回兩次,因為操作系統(tǒng)自動把當前進程(稱為父進程)復制了一份(稱為子進程),然后,分別在父進程和子進程內(nèi)返回
2) 子進程永遠返回0,而父進程返回子進程的ID
3) 一個父進程可以fork出很多子進程,所以,父進程要記下每個子進程 的ID,而子進程中需要調(diào)用getppid()就可以拿到父進程的id
4) 父進程、子進程執(zhí)行順序沒有規(guī)律,完全取決于操作系統(tǒng)的調(diào)度算法
進程擁有獨立的運行空間,變量的值不能共享
由于python是跨平臺的,自然也應該提供一個跨平臺的多進程支持。multiprocessing模塊就是跨平臺版本的多進程模塊
multiprocessing模塊提供了一個process類來代表一個進程對象
創(chuàng)建子進程時,只需要傳入一個執(zhí)行函數(shù)和函數(shù)的參數(shù),創(chuàng)建一個Process實例,用start()方法啟動,這樣創(chuàng)建進程比fork()還要簡單
Process([group [,target [,name [,args [,kwargs]]]]])
target | 表示這個進程實例所調(diào)用對象 |
args | 表示調(diào)用對象的位置參數(shù),元組 |
kwargs | 表示調(diào)用對象的關鍵字參數(shù),字典 |
name | 為當前進程實例的別名 |
group | 創(chuàng)建一個進程組,大多數(shù)情況下用不到 |
Process類常用方法 |
join()方法 | 可以等待子進程結(jié)束后再繼續(xù)往下運行,通常用于進程間的同步 |
is_alive() | 判斷進程實例是否還在執(zhí)行 |
join([timeout]) | 是否等待進程實例執(zhí)行結(jié)束,或等待多少秒 |
start() | 啟動進程實例(創(chuàng)建子進程) |
run() | 如果沒有給定target參數(shù),對這個對象調(diào)用start()方法時,就將執(zhí)行對象中的run()方法 |
terminate() | 不管任務是否完成,立即終止 |
Process類常用屬性 |
name | 當前進程實例別名,默認為Process-N,N為從1開始遞增的整數(shù) |
pid | 當前進程實例的pid值 |
例1
例2
創(chuàng)建新的的進程還能夠使用類的方式,可以自定義一個類,繼承Process類,每次實例化這個類的的時候,就等同于實例化一個進程對象
例,創(chuàng)建多個進程
multiprocessing的Pool方法
當需要創(chuàng)建的子進程數(shù)量不多時,可以直接利用multiprocessing中的Process動態(tài)生成多個進程,但如果是上百甚至上千個目標,手動去創(chuàng)建進程進程的工作量巨大,此時就可可以用到到multiprocessing模塊提供的Pool方法
初始化Pool時,可以指定一個最大進程數(shù),當有有新的請求提交到Pool時,如果池還沒滿,那么就會創(chuàng)建一一個新的進程用來執(zhí)行該請求,但如果池中的進程數(shù)已經(jīng)達到到指定的最大值,那么該請求就會會等待,直到池中有進程結(jié)束,才會創(chuàng)建新的進程來執(zhí)行。
multiprocessing.Pool常用函數(shù)解析
apply_async(func[,args[,kwds]]):使用非阻塞阻塞方式調(diào)用func(并行執(zhí)行,堵塞方式必須等待上一個進程退出才能執(zhí)行下一個進程進程),args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關鍵字參數(shù)參數(shù)列表;
apply(func[,args[,kwds]]):使用阻塞方式調(diào)用func
close():關閉Pool,使其不再接受新的任務。不是馬上關,執(zhí)行中的任務仍會執(zhí)行。
terminate():不管任務是否完成,立即終止
join():主進程阻塞,等待子進程的退出,必須在colse或terminate之后使用
例,
| |
異步,非阻塞 | 同步,阻塞 |
消息隊列
操作系統(tǒng)提供了很多機制來實現(xiàn)進程間的通信 ,multiprocessing模塊就提供了Queue和Pipe兩種方法來實現(xiàn)
Queue模塊專門實現(xiàn)消息隊列Queue對象。
queue只有maxsize一個構(gòu)造參數(shù),用來指定隊列容量,指定為0的時候代表容量無限。
主要有以下成員函數(shù):
Queue.qsize():返回消息隊列的當前空間。返回的值不一定可靠。
Queue.empty():判斷消息隊列是否為空,返回True或False。同樣不可靠。
Queue.full():類似上邊,判斷消息隊列是否滿
Queue.put(item, block=True, timeout=None):往消息隊列中存放消息。block可以控制是否阻塞,timeout指定阻塞時候的等待時間。如果不阻塞或者超時,會引起一個full exception。
Queue.put_nowait(item):相當于put(item, False).Queue.get(block=True, timeout=None):獲取一個消息,其他同put。