學(xué)習(xí)完如何創(chuàng)建進(jìn)程之后,我們可以通過多次調(diào)用的方式創(chuàng)建多個(gè)進(jìn)程,那么每個(gè)進(jìn)程之間的信息是怎么樣的,它們又是如何進(jìn)行通信的,它們能否直接共用一些資源呢,下面我們通過一個(gè)例子來了解一下。
from multiprocessing import Process number = 100 def change():#為擬創(chuàng)建的子進(jìn)程1提供方法 print('子進(jìn)程1開始運(yùn)行') global number number += 10 print('把number加10等于:%d'%number) print('子進(jìn)程1結(jié)束') def changes():#為擬創(chuàng)建的子進(jìn)程2提供方法 print('子進(jìn)程2開始運(yùn)行') global number number += 20 print('把number加20等于:%d'%number) print('子進(jìn)程2結(jié)束') if __name__ == '__main__': process_one = Process(target=change) process_one.start()#啟動(dòng)進(jìn)程 process_one.join()#等待進(jìn)程執(zhí)行結(jié)束 process_two = Process(target=changes) process_two.start()#啟動(dòng)進(jìn)程 process_two.join()#等待進(jìn)程執(zhí)行結(jié)束 print('number最后為:%d'%number)
運(yùn)行結(jié)果為:
子進(jìn)程1開始運(yùn)行 把number加10等于:110 子進(jìn)程1結(jié)束 子進(jìn)程2開始運(yùn)行 把number加20等于:120 子進(jìn)程2結(jié)束 number最后為:100
我們通過輸出結(jié)果可以看出,即使他們共用的是一個(gè)資源number,但是都沒有影響number的最終數(shù)值,也就是第一個(gè)使用過的資源并沒有被用在第二個(gè)進(jìn)程當(dāng)中,資源沒有共享,如果要實(shí)現(xiàn)進(jìn)程間通信,Python在multiprocessing模塊中提供了Queue、pipes等多種方法來進(jìn)行數(shù)據(jù)的交換,我們下面來學(xué)習(xí)一下使用隊(duì)列Queue來完成進(jìn)程間的通信。
1. 隊(duì)列
學(xué)過數(shù)據(jù)結(jié)構(gòu)的同學(xué)一定對這個(gè)詞不陌生,隊(duì)列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作,進(jìn)行插入操作的端稱為隊(duì)尾,進(jìn)行刪除操作的端稱為隊(duì)頭。
我們也可以通過生活中的排隊(duì)機(jī)制來理解一下隊(duì)列,當(dāng)一座橋只能允許一輛車通過的時(shí)候,那么新到來的車只能排在隊(duì)伍的末尾來通過這座橋,而隊(duì)列中間的車是無法直接離開橋的,只有等排在隊(duì)頭的車通過了之后才能過橋。
如圖:
甲剛剛從隊(duì)頭出隊(duì),那么緊接著乙可以出隊(duì),后續(xù)的繼續(xù)等待,當(dāng)甲出隊(duì)之后,戊可以準(zhǔn)備入隊(duì)。
2. 多進(jìn)程隊(duì)列
在Python中,multiprocessing模塊中存在Queue類幫我們實(shí)現(xiàn)多進(jìn)程之間的數(shù)據(jù)交互,初始化一個(gè)Queue對象的方式為:my_queue = Queue(count),還有一些常用的方法:
Queue.qsize():返回隊(duì)列中的信息數(shù)量。
Queue.empty():如果隊(duì)列為空,則返回True,否則為false。由于多線程/多處理語義,這是不可靠的。
Queue.full():如果隊(duì)列已滿,則返回true,否則返回false。
Queue.put(obj[, block[, timeout]]):將obj放入隊(duì)列中,如果可選參數(shù)塊為True(默認(rèn)值),超時(shí)為None(默認(rèn)值),則必要時(shí)阻塞,直到空閑插槽可用為止。如果超時(shí)為正數(shù),則為b 鎖定最多超時(shí)秒并提高隊(duì)列。
Queue.get([block[, timeout]]) :從隊(duì)列中移除并返回一個(gè)項(xiàng)。如果可選args塊為True (默認(rèn)值),超時(shí)為None(默認(rèn)值)。
還有更多的用法大家可以在Python文檔中去進(jìn)一步了解。
下面我們通過一個(gè)例子來實(shí)現(xiàn)多進(jìn)程隊(duì)列的通信,假設(shè)有一個(gè)停車場,有停車和開走車兩個(gè)操作,下面我們要在程序中寫兩個(gè)子進(jìn)程,其中一個(gè)進(jìn)程往進(jìn)程中停放車輛,另外一個(gè)子進(jìn)程把車輛開出去,代碼如下:
from multiprocessing import Process,Queue import time import datetime #往停車場中停入車輛 def park(x): if not x.full(): for i in range(5): car = '車輛'+str(i) x.put(car) print('停入:%s 時(shí)間:%s'%(car,datetime.datetime.now())) #開走車輛 def drive(x): time.sleep(2)#休眠2s while not x.empty(): print('開走:%s時(shí)間:%s'%(x.get(True,3),datetime.datetime.now())) if __name__ == '__main__': x = Queue()#創(chuàng)建一個(gè)隊(duì)列 p = Process(target=park,args=(x,))#創(chuàng)建一個(gè)進(jìn)程,并放入隊(duì)列中 d = Process(target=drive,args=(x,))#創(chuàng)建一個(gè)進(jìn)程,并放入隊(duì)列中 p.start()#啟動(dòng) d.start()#啟動(dòng) p.join() d.join()
輸出結(jié)果如下:
停入:車輛0 時(shí)間:2020-02-10 10:48:01.290038 停入:車輛1 時(shí)間:2020-02-10 10:48:01.290038 停入:車輛2 時(shí)間:2020-02-10 10:48:01.290038 停入:車輛3 時(shí)間:2020-02-10 10:48:01.291037 停入:車輛4 時(shí)間:2020-02-10 10:48:01.291037 開走:車輛0 時(shí)間:2020-02-10 10:48:03.292486 開走:車輛1 時(shí)間:2020-02-10 10:48:03.292486 開走:車輛2 時(shí)間:2020-02-10 10:48:03.292486 開走:車輛3 時(shí)間:2020-02-10 10:48:03.292486 開走:車輛4 時(shí)間:2020-02-10 10:48:03.292486
3. 總結(jié)
學(xué)習(xí)完了這一節(jié),進(jìn)程和線程也就結(jié)束了,本章我們主要了解了如何創(chuàng)建他們,然后就是如何使用他們進(jìn)行通信,另外我們還學(xué)習(xí)了線程安全和線程管理,這些內(nèi)容對于操作系統(tǒng)而言是很重要的內(nèi)容,想要了解更多的知識(shí),可以去查看Python文檔或者去查閱操作系統(tǒng)的相關(guān)書籍。
C語言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:
一點(diǎn)編程也不會(huì)寫的:零基礎(chǔ)C語言學(xué)練課程
解決困擾你多年的C語言疑難雜癥特性的C語言進(jìn)階課程
從零到寫出一個(gè)爬蟲的Python編程課程
只會(huì)語法寫不出代碼?手把手帶你寫100個(gè)編程真題的編程百練課程
信息學(xué)奧賽或C++選手的 必學(xué)C++課程
藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競賽課入門課程
手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程