python并發(fā)編程 Process對(duì)象的其他屬性方法join方法詳解
一 Process對(duì)象的join方法
在主進(jìn)程運(yùn)行過(guò)程中如果想并發(fā)地執(zhí)行其他的任務(wù),我們可以開(kāi)啟子進(jìn)程,此時(shí)主進(jìn)程的任務(wù)與子進(jìn)程的任務(wù)分兩種情況
情況一:
在主進(jìn)程的任務(wù)與子進(jìn)程的任務(wù)彼此獨(dú)立的情況下,主進(jìn)程的任務(wù)先執(zhí)行完畢后,主進(jìn)程還需要等待子進(jìn)程執(zhí)行完畢,然后統(tǒng)一回收資源。 這種是沒(méi)有join方法
情況二:
如果主進(jìn)程的任務(wù)在執(zhí)行到某一個(gè)階段時(shí),需要等待子進(jìn)程執(zhí)行完畢后才能繼續(xù)執(zhí)行,
就需要有一種機(jī)制能夠讓主進(jìn)程檢測(cè)子進(jìn)程是否運(yùn)行完畢,在子進(jìn)程執(zhí)行完畢后才繼續(xù)執(zhí)行,否則一直在原地阻塞,這就是join方法的作用
讓主進(jìn)程等著,所有子進(jìn)程執(zhí)行完畢后,主進(jìn)程才繼續(xù)執(zhí)行
from multiprocessing import Process import time import os def task(): print("%s is running,parent id is <%s>" % (os.getpid(), os.getppid())) time.sleep(3) print("%s is done,parent id is <%s>" % (os.getpid(), os.getppid())) if __name__ == "__main__": t = Process(target=task, ) t.start() t.join() # 主進(jìn)程 等子進(jìn)程執(zhí)行完了 print("主", os.getpid(), os.getppid()) ''' is running,parent id is <25956> is done,parent id is <25956> 主 25956 2992 '''
子進(jìn)程運(yùn)行完,最后打印主進(jìn)程,主進(jìn)程結(jié)束了 所有僵尸進(jìn)程都會(huì)回收
開(kāi)啟多個(gè)字進(jìn)程 向操作系統(tǒng)發(fā)送信號(hào),但操作系統(tǒng)要處理的任務(wù)太多了,先開(kāi)啟 哪個(gè)子進(jìn)程是隨機(jī)的,有時(shí)候可能先開(kāi)啟主進(jìn)程先,
操作系統(tǒng)什么時(shí)候開(kāi),開(kāi)多長(zhǎng)時(shí)間,我們是不知道的
from multiprocessing import Process import time import os def task(name): print('%s is running' %name) time.sleep(2) print('%s is end' %name) if __name__ == '__main__': p1 = Process(target=task, args=('子進(jìn)程1',)) p2 = Process(target=task, args=('子進(jìn)程2',)) p3 = Process(target=task, args=('子進(jìn)程3',)) p4 = Process(target=task, args=('子進(jìn)程4',)) p1.start() p2.start() p3.start() p4.start() print('主',os.getpid(),os.getppid()) ''' 子進(jìn)程1 is running 子進(jìn)程2 is running 主 9268 5236 子進(jìn)程3 is running 子進(jìn)程4 is running 子進(jìn)程1 is end 子進(jìn)程2 is end 子進(jìn)程3 is end 子進(jìn)程4 is end '''
也有可能這樣,先開(kāi)啟主進(jìn)程,
主 9556 5236 子進(jìn)程1 is running 子進(jìn)程3 is running 子進(jìn)程2 is running 子進(jìn)程4 is running 子進(jìn)程1 is end 子進(jìn)程3 is end 子進(jìn)程2 is end 子進(jìn)程4 is end
p.start() 只是給操作系統(tǒng)發(fā)送信號(hào)
join 會(huì)變串行?
既然join是等待進(jìn)程結(jié)束, 那么我像下面這樣寫(xiě), 進(jìn)程不就又變成串行的了嗎?
當(dāng)然不是了, 必須明確:p.join()是讓誰(shuí)等?
很明顯p.join()是讓主線程等待p 子進(jìn)程的結(jié)束,卡住的是主進(jìn)程而絕非 子進(jìn)程p,
from multiprocessing import Process import time import os def task(name): print('%s is running' %(name)) time.sleep(2) print('%s is end' %(name)) if __name__ == '__main__': p1 = Process(target=task, args=('子進(jìn)程1',)) p2 = Process(target=task, args=('子進(jìn)程2',)) p3 = Process(target=task, args=('子進(jìn)程3',)) p4 = Process(target=task, args=('子進(jìn)程4',)) p1.start() p2.start() p3.start() p4.start() p1.join() p2.join() p3.join() p4.join() print('主',os.getpid(),os.getppid())
詳細(xì)解析如下:
進(jìn)程只要start就會(huì)在開(kāi)始運(yùn)行了,所以p1-p4.start()時(shí),系統(tǒng)中已經(jīng)有四個(gè)并發(fā)的進(jìn)程了
而我們p1.join()是在等p1結(jié)束,沒(méi)錯(cuò)p1只要不結(jié)束主線程就會(huì)一直卡在原地,這也是問(wèn)題的關(guān)鍵
join是讓主線程等,而p1-p4仍然是并發(fā)執(zhí)行的,p1.join的時(shí)候,其余p2,p3,p4仍然在運(yùn)行,等#p1.join結(jié)束,可能p2,p3,p4早已經(jīng)結(jié)束了,這樣p2.join,p3.join.p4.join直接通過(guò)檢測(cè),無(wú)需等待
所以4個(gè)join花費(fèi)的總時(shí)間仍然是耗費(fèi)時(shí)間最長(zhǎng)的那個(gè)進(jìn)程運(yùn)行的時(shí)間
所以不會(huì)是串行執(zhí)行,是并發(fā)執(zhí)行
4個(gè)join花費(fèi)的總時(shí)間仍然是耗費(fèi)時(shí)間最長(zhǎng)的那個(gè)進(jìn)程運(yùn)行的時(shí)間
所以就是5秒,就是子進(jìn)程1 那個(gè)等待的時(shí)間
from multiprocessing import Process import time import os def task(name,n): print('%s is running' %(name)) time.sleep(n) print('%s is end' %(name)) if __name__ == '__main__': start = time.time() p1 = Process(target=task, args=('子進(jìn)程1',5)) p2 = Process(target=task, args=('子進(jìn)程2',2)) p3 = Process(target=task, args=('子進(jìn)程3',2)) p4 = Process(target=task, args=('子進(jìn)程4',2)) p1.start() p2.start() p3.start() p4.start() p1.join() p2.join() p3.join() p4.join() print('主',time.time() - start) ''' 子進(jìn)程1 is running 子進(jìn)程2 is running 子進(jìn)程3 is running 子進(jìn)程4 is running 子進(jìn)程2 is end 子進(jìn)程3 is end 子進(jìn)程4 is end 子進(jìn)程1 is end 主 5.413309812545776 '''
這種方式就是串行
等子進(jìn)程1執(zhí)行時(shí)候,子進(jìn)程2就沒(méi)有發(fā)送信號(hào),要等子進(jìn)程1 執(zhí)行完,再子進(jìn)程2發(fā)送信號(hào) ,開(kāi)啟子進(jìn)程2再執(zhí)行,按照這樣的順序
from multiprocessing import Process import time import os def task(name,n): print('%s is running' %(name)) time.sleep(n) print('%s is end' %(name)) if __name__ == '__main__': start = time.time() p1 = Process(target=task, args=('子進(jìn)程1',5)) p2 = Process(target=task, args=('子進(jìn)程2',2)) p3 = Process(target=task, args=('子進(jìn)程3',2)) p4 = Process(target=task, args=('子進(jìn)程4',2)) p1.start() p1.join() p2.start() p2.join() p3.start() p3.join() p4.start() p4.join() print('主',time.time() - start) ''' 子進(jìn)程1 is running 子進(jìn)程1 is end 子進(jìn)程2 is running 子進(jìn)程2 is end 子進(jìn)程3 is running 子進(jìn)程3 is end 子進(jìn)程4 is running 子進(jìn)程4 is end 主 12.212698698043823 '''
上述啟動(dòng)進(jìn)程與 join進(jìn)程 可以簡(jiǎn)寫(xiě)為以下
from multiprocessing import Process import time import os def task(name,n): print('%s is running' %(name)) time.sleep(n) print('%s is end' %(name)) if __name__ == '__main__': start = time.time() p1 = Process(target=task, args=('子進(jìn)程1',5)) p2 = Process(target=task, args=('子進(jìn)程2',2)) p3 = Process(target=task, args=('子進(jìn)程3',2)) p4 = Process(target=task, args=('子進(jìn)程4',2)) process_list = [p1,p2,p3,p4] for p in process_list: p.start() for p in process_list: p.join() print('主',time.time() - start)
join 保證所有子進(jìn)程執(zhí)行完 主進(jìn)程才能工作,不然一直阻塞
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python實(shí)現(xiàn)動(dòng)態(tài)給類和對(duì)象添加屬性和方法操作示例
- python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5控件QTableWidget詳細(xì)使用方法與屬性
- Python os模塊常用方法和屬性總結(jié)
- python圖形開(kāi)發(fā)GUI庫(kù)pyqt5的詳細(xì)使用方法及各控件的屬性與方法
- python隱藏類中屬性的3種實(shí)現(xiàn)方法
- python-web根據(jù)元素屬性進(jìn)行定位的方法
- Python 類的私有屬性和私有方法實(shí)例分析
- Python面向?qū)ο筇厥鈱傩约胺椒ń馕?/a>
相關(guān)文章
PyQt5+QtChart實(shí)現(xiàn)柱狀圖的繪制
QChart是一個(gè)QGraphicScene中可以顯示的QGraphicsWidget。本文將利用QtChart實(shí)現(xiàn)柱狀圖的繪制,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12手把手教你如何用Pycharm2020.1.1配置遠(yuǎn)程連接的詳細(xì)步驟
這篇文章主要介紹了如何用Pycharm2020.1.1配置遠(yuǎn)程連接,分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-08-08Python實(shí)現(xiàn)的棧、隊(duì)列、文件目錄遍歷操作示例
這篇文章主要介紹了Python實(shí)現(xiàn)的棧、隊(duì)列、文件目錄遍歷操作,結(jié)合實(shí)例形式分析了Python數(shù)據(jù)結(jié)構(gòu)中棧與隊(duì)列的定義、使用,以及文件目錄的遍歷相關(guān)操作技巧,需要的朋友可以參考下2019-05-05Python實(shí)現(xiàn)捕獲異常發(fā)生的文件和具體行數(shù)
這篇文章主要介紹了Python實(shí)現(xiàn)捕獲異常發(fā)生的文件和具體行數(shù)。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04Python設(shè)計(jì)模式之模板方法模式實(shí)例詳解
這篇文章主要介紹了Python設(shè)計(jì)模式之模板方法模式,結(jié)合實(shí)例形式較為詳細(xì)的分析了模板方法模式的概念、原理及Python定義、使用模板方法模式相關(guān)操作技巧,需要的朋友可以參考下2019-01-01Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的畢業(yè)生信息管理系統(tǒng)的示例代碼
這篇文章主要介紹了Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的畢業(yè)生信息管理系統(tǒng)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06基于keras輸出中間層結(jié)果的2種實(shí)現(xiàn)方式
今天小編就為大家分享一篇基于keras輸出中間層結(jié)果的2種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01