1. 多進(jìn)程
程序:program是一個(gè)指令的集合
進(jìn)程:process,正在執(zhí)行中的程序,是一個(gè)靜態(tài)的概念
1) 進(jìn)程是程序的一次靜態(tài)執(zhí)行過(guò)程,占用特定的地址空間
2) 每個(gè)進(jìn)程都是獨(dú)立的,由3部分組成cpu,data,code
3) 缺點(diǎn):內(nèi)存的浪費(fèi),cpu的負(fù)擔(dān)
4) 數(shù)據(jù)區(qū)、代碼區(qū)、堆、棧
操作系統(tǒng)輪流讓各個(gè)任務(wù)交替執(zhí)行,由于CPU的執(zhí)行速度實(shí)在是太快了,我們感覺(jué)就像所有任務(wù)都在同時(shí)執(zhí)行一樣
真正的并行執(zhí)行多任務(wù)只能在多核心CPU上實(shí)現(xiàn),但是,由于任務(wù)數(shù)據(jù)遠(yuǎn)遠(yuǎn)多于CPU的核心數(shù)量,所以,操作系統(tǒng)也會(huì)自動(dòng)把很多任務(wù)輪流調(diào)度到每個(gè)核心上執(zhí)行
在unix/linux操作系統(tǒng)中,提供了一個(gè)fork()系統(tǒng)函數(shù),它非常特殊
1) 普通的函數(shù)調(diào)用,調(diào)用一次,返回一次,但是fork()調(diào)用一次,返回兩次,因?yàn)椴僮飨到y(tǒng)自動(dòng)把當(dāng)前進(jìn)程(稱為父進(jìn)程)復(fù)制了一份(稱為子進(jìn)程),然后,分別在父進(jìn)程和子進(jìn)程內(nèi)返回
2) 子進(jìn)程永遠(yuǎn)返回0,而父進(jìn)程返回子進(jìn)程的ID
3) 一個(gè)父進(jìn)程可以fork出很多子進(jìn)程,所以,父進(jìn)程要記下每個(gè)子進(jìn)程 的ID,而子進(jìn)程中需要調(diào)用getppid()就可以拿到父進(jìn)程的id
4) 父進(jìn)程、子進(jìn)程執(zhí)行順序沒(méi)有規(guī)律,完全取決于操作系統(tǒng)的調(diào)度算法

進(jìn)程擁有獨(dú)立的運(yùn)行空間,變量的值不能共享


由于python是跨平臺(tái)的,自然也應(yīng)該提供一個(gè)跨平臺(tái)的多進(jìn)程支持。multiprocessing模塊就是跨平臺(tái)版本的多進(jìn)程模塊
multiprocessing模塊提供了一個(gè)process類來(lái)代表一個(gè)進(jìn)程對(duì)象

創(chuàng)建子進(jìn)程時(shí),只需要傳入一個(gè)執(zhí)行函數(shù)和函數(shù)的參數(shù),創(chuàng)建一個(gè)Process實(shí)例,用start()方法啟動(dòng),這樣創(chuàng)建進(jìn)程比fork()還要簡(jiǎn)單
Process([group [,target [,name [,args [,kwargs]]]]])
target | 表示這個(gè)進(jìn)程實(shí)例所調(diào)用對(duì)象 |
args | 表示調(diào)用對(duì)象的位置參數(shù),元組 |
kwargs | 表示調(diào)用對(duì)象的關(guān)鍵字參數(shù),字典 |
name | 為當(dāng)前進(jìn)程實(shí)例的別名 |
group | 創(chuàng)建一個(gè)進(jìn)程組,大多數(shù)情況下用不到 |
Process類常用方法 |
join()方法 | 可以等待子進(jìn)程結(jié)束后再繼續(xù)往下運(yùn)行,通常用于進(jìn)程間的同步 |
is_alive() | 判斷進(jìn)程實(shí)例是否還在執(zhí)行 |
join([timeout]) | 是否等待進(jìn)程實(shí)例執(zhí)行結(jié)束,或等待多少秒 |
start() | 啟動(dòng)進(jìn)程實(shí)例(創(chuàng)建子進(jìn)程) |
run() | 如果沒(méi)有給定target參數(shù),對(duì)這個(gè)對(duì)象調(diào)用start()方法時(shí),就將執(zhí)行對(duì)象中的run()方法 |
terminate() | 不管任務(wù)是否完成,立即終止 |
Process類常用屬性 |
name | 當(dāng)前進(jìn)程實(shí)例別名,默認(rèn)為Process-N,N為從1開(kāi)始遞增的整數(shù) |
pid | 當(dāng)前進(jìn)程實(shí)例的pid值 |
例1

例2

創(chuàng)建新的的進(jìn)程還能夠使用類的方式,可以自定義一個(gè)類,繼承Process類,每次實(shí)例化這個(gè)類的的時(shí)候,就等同于實(shí)例化一個(gè)進(jìn)程對(duì)象

例,創(chuàng)建多個(gè)進(jìn)程

multiprocessing的Pool方法
當(dāng)需要?jiǎng)?chuàng)建的子進(jìn)程數(shù)量不多時(shí),可以直接利用multiprocessing中的Process動(dòng)態(tài)生成多個(gè)進(jìn)程,但如果是上百甚至上千個(gè)目標(biāo),手動(dòng)去創(chuàng)建進(jìn)程進(jìn)程的工作量巨大,此時(shí)就可可以用到到multiprocessing模塊提供的Pool方法
初始化Pool時(shí),可以指定一個(gè)最大進(jìn)程數(shù),當(dāng)有有新的請(qǐng)求提交到Pool時(shí),如果池還沒(méi)滿,那么就會(huì)創(chuàng)建一一個(gè)新的進(jìn)程用來(lái)執(zhí)行該請(qǐng)求,但如果池中的進(jìn)程數(shù)已經(jīng)達(dá)到到指定的最大值,那么該請(qǐng)求就會(huì)會(huì)等待,直到池中有進(jìn)程結(jié)束,才會(huì)創(chuàng)建新的進(jìn)程來(lái)執(zhí)行。
multiprocessing.Pool常用函數(shù)解析
apply_async(func[,args[,kwds]]):使用非阻塞阻塞方式調(diào)用func(并行執(zhí)行,堵塞方式必須等待上一個(gè)進(jìn)程退出才能執(zhí)行下一個(gè)進(jìn)程進(jìn)程),args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)參數(shù)列表;
apply(func[,args[,kwds]]):使用阻塞方式調(diào)用func
close():關(guān)閉Pool,使其不再接受新的任務(wù)。不是馬上關(guān),執(zhí)行中的任務(wù)仍會(huì)執(zhí)行。
terminate():不管任務(wù)是否完成,立即終止
join():主進(jìn)程阻塞,等待子進(jìn)程的退出,必須在colse或terminate之后使用
例,

| 
|
異步,非阻塞 | 同步,阻塞 |
消息隊(duì)列
操作系統(tǒng)提供了很多機(jī)制來(lái)實(shí)現(xiàn)進(jìn)程間的通信 ,multiprocessing模塊就提供了Queue和Pipe兩種方法來(lái)實(shí)現(xiàn)
Queue模塊專門實(shí)現(xiàn)消息隊(duì)列Queue對(duì)象。
queue只有maxsize一個(gè)構(gòu)造參數(shù),用來(lái)指定隊(duì)列容量,指定為0的時(shí)候代表容量無(wú)限。
主要有以下成員函數(shù):
Queue.qsize():返回消息隊(duì)列的當(dāng)前空間。返回的值不一定可靠。
Queue.empty():判斷消息隊(duì)列是否為空,返回True或False。同樣不可靠。
Queue.full():類似上邊,判斷消息隊(duì)列是否滿
Queue.put(item, block=True, timeout=None):往消息隊(duì)列中存放消息。block可以控制是否阻塞,timeout指定阻塞時(shí)候的等待時(shí)間。如果不阻塞或者超時(shí),會(huì)引起一個(gè)full exception。
Queue.put_nowait(item):相當(dāng)于put(item, False).Queue.get(block=True, timeout=None):獲取一個(gè)消息,其他同put。