python并發(fā)編程 Process對象的其他屬性方法join方法詳解
一 Process對象的join方法
在主進(jìn)程運(yùn)行過程中如果想并發(fā)地執(zhí)行其他的任務(wù),我們可以開啟子進(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)一回收資源。 這種是沒有join方法
情況二:
如果主進(jìn)程的任務(wù)在執(zhí)行到某一個(gè)階段時(shí),需要等待子進(jìn)程執(zhí)行完畢后才能繼續(xù)執(zhí)行,
就需要有一種機(jī)制能夠讓主進(jìn)程檢測子進(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)程都會回收
開啟多個(gè)字進(jìn)程 向操作系統(tǒng)發(fā)送信號,但操作系統(tǒng)要處理的任務(wù)太多了,先開啟 哪個(gè)子進(jìn)程是隨機(jī)的,有時(shí)候可能先開啟主進(jìn)程先,
操作系統(tǒng)什么時(shí)候開,開多長時(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
'''
也有可能這樣,先開啟主進(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ā)送信號
join 會變串行?
既然join是等待進(jìn)程結(jié)束, 那么我像下面這樣寫, 進(jìn)程不就又變成串行的了嗎?
當(dāng)然不是了, 必須明確:p.join()是讓誰等?
很明顯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就會在開始運(yùn)行了,所以p1-p4.start()時(shí),系統(tǒng)中已經(jīng)有四個(gè)并發(fā)的進(jìn)程了
而我們p1.join()是在等p1結(jié)束,沒錯(cuò)p1只要不結(jié)束主線程就會一直卡在原地,這也是問題的關(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直接通過檢測,無需等待
所以4個(gè)join花費(fèi)的總時(shí)間仍然是耗費(fèi)時(shí)間最長的那個(gè)進(jìn)程運(yùn)行的時(shí)間
所以不會是串行執(zhí)行,是并發(fā)執(zhí)行
4個(gè)join花費(fèi)的總時(shí)間仍然是耗費(fèi)時(shí)間最長的那個(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就沒有發(fā)送信號,要等子進(jìn)程1 執(zhí)行完,再子進(jìn)程2發(fā)送信號 ,開啟子進(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
'''
上述啟動進(jìn)程與 join進(jìn)程 可以簡寫為以下
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)程才能工作,不然一直阻塞
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于vscode?默認(rèn)添加python項(xiàng)目的源目錄路徑到執(zhí)行環(huán)境的問題
這篇文章主要介紹了vscode?默認(rèn)添加python項(xiàng)目的源目錄路徑到執(zhí)行環(huán)境,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
ubuntu環(huán)境下python虛擬環(huán)境的安裝過程
這篇文章主要介紹了ubuntu環(huán)境下python虛擬環(huán)境的安裝搭建過程 ,需要的朋友可以參考下2018-01-01
Python調(diào)用ChatGPT的API實(shí)現(xiàn)文章生成
最近ChatGPT大火,在3.5版本后開放了接口API,所以很多人開始進(jìn)行實(shí)操,這里我就用python來為大家實(shí)現(xiàn)一下,如何調(diào)用API并提問返回文章的說明2023-03-03
Python使用bar繪制堆積/帶誤差棒柱形圖的實(shí)現(xiàn)
本文先講解bar參數(shù)如何使用,然后分別演示堆積柱形圖和帶誤差柱形圖畫法。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
python數(shù)據(jù)可視化plt庫實(shí)例詳解
這篇文章主要介紹了python可視化數(shù)據(jù)plt庫實(shí)例,下面使用pycharm環(huán)境給大家詳細(xì)介紹,文中提到j(luò)upyter和pycharm環(huán)境的差別,需要的朋友可以參考下2021-06-06
Python中的Socket 與 ScoketServer 通信及遇到問題解決方法
Socket有一個(gè)緩沖區(qū),緩沖區(qū)是一個(gè)流,先進(jìn)先出,發(fā)送和取出的可自定義大小的,如果取出的數(shù)據(jù)未取完緩沖區(qū),則可能存在數(shù)據(jù)怠慢。本文通過實(shí)例代碼給大家介紹Python中的Socket 與 ScoketServer 通信及遇到問題解決方法 ,需要的朋友參考下吧2019-04-04

