Python多線程與多進(jìn)程中join()方法的效果是相同的。
下面僅以多線程為例:
首先需要明確幾個(gè)概念:
知識(shí)點(diǎn)一:
當(dāng)一個(gè)進(jìn)程啟動(dòng)之后迟赃,會(huì)默認(rèn)產(chǎn)生一個(gè)主線程厂镇,因?yàn)榫€程是程序執(zhí)行流的最小單元,當(dāng)設(shè)置多線程時(shí)捺信,主線程會(huì)創(chuàng)建多個(gè)子線程,在python中馍佑,默認(rèn)情況下(其實(shí)就是setDaemon(False))拭荤,主線程執(zhí)行完自己的任務(wù)以后疫诽,就退出了,此時(shí)子線程會(huì)繼續(xù)執(zhí)行自己的任務(wù)雏亚,直到自己的任務(wù)結(jié)束缨硝,例子見(jiàn)下面一。
知識(shí)點(diǎn)二:
當(dāng)我們使用setDaemon(True)方法罢低,設(shè)置子線程為守護(hù)線程時(shí)查辩,主線程一旦執(zhí)行結(jié)束,則全部線程全部被終止執(zhí)行网持,可能出現(xiàn)的情況就是宜岛,子線程的任務(wù)還沒(méi)有完全執(zhí)行結(jié)束,就被迫停止功舀,例子見(jiàn)下面二萍倡。
知識(shí)點(diǎn)三:
此時(shí)join的作用就凸顯出來(lái)了,join所完成的工作就是線程同步辟汰,即主線程任務(wù)結(jié)束之后列敲,進(jìn)入阻塞狀態(tài),一直等待其他的子線程執(zhí)行結(jié)束之后帖汞,主線程在終止戴而,例子見(jiàn)下面三。
知識(shí)點(diǎn)四:
join有一個(gè)timeout參數(shù):
- 當(dāng)設(shè)置守護(hù)線程時(shí)涨冀,含義是主線程對(duì)于子線程等待timeout的時(shí)間將會(huì)殺死該子線程鹿鳖,最后退出程序。所以說(shuō)涝滴,如果有10個(gè)子線程,全部的等待時(shí)間就是每個(gè)timeout的累加和诈唬。簡(jiǎn)單的來(lái)說(shuō)赡矢,就是給每個(gè)子線程一個(gè)timeout的時(shí)間弧械,讓他去執(zhí)行,時(shí)間一到唁桩,不管任務(wù)有沒(méi)有完成,直接殺死单山。
- 沒(méi)有設(shè)置守護(hù)線程時(shí),主線程將會(huì)等待timeout的累加和這樣的一段時(shí)間悴晰,時(shí)間一到,主線程結(jié)束棕硫,但是并沒(méi)有殺死子線程,子線程依然可以繼續(xù)執(zhí)行滑肉,直到子線程全部結(jié)束,程序退出惶洲。
一:Python多線程的默認(rèn)情況
import threading
import time
def run():
time.sleep(2)
print('當(dāng)前線程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('這是主線程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.start()
print('主線程結(jié)束!' , threading.current_thread().name)
print('一共用時(shí):', time.time()-start_time)
其執(zhí)行結(jié)果如下
關(guān)鍵點(diǎn):
- 我們的計(jì)時(shí)是對(duì)主線程計(jì)時(shí),主線程結(jié)束柒凉,計(jì)時(shí)隨之結(jié)束,打印出主線程的用時(shí)蔬咬。
- 主線程的任務(wù)完成之后,主線程隨之結(jié)束狐援,子線程繼續(xù)執(zhí)行自己的任務(wù),直到全部的子線程的任務(wù)全部結(jié)束,程序結(jié)束。
二:設(shè)置守護(hù)線程
import threading
import time
def run():
time.sleep(2)
print('當(dāng)前線程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('這是主線程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.setDaemon(True)
t.start()
print('主線程結(jié)束了!' , threading.current_thread().name)
print('一共用時(shí):', time.time()-start_time)
其執(zhí)行結(jié)果如下,注意請(qǐng)確保setDaemon()在start()之前疫粥。
關(guān)鍵點(diǎn):
- 非常明顯的看到娄蔼,主線程結(jié)束以后,子線程還沒(méi)有來(lái)得及執(zhí)行涕癣,整個(gè)程序就退出了。
三:join的作用
import threading
import time
def run():
time.sleep(2)
print('當(dāng)前線程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('這是主線程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.setDaemon(True)
t.start()
for t in thread_list:
t.join()
print('主線程結(jié)束了须蜗!' , threading.current_thread().name)
print('一共用時(shí):', time.time()-start_time)
其執(zhí)行結(jié)果如下:
關(guān)鍵點(diǎn):
- 可以看到,主線程一直等待全部的子線程結(jié)束之后柿估,主線程自身才結(jié)束足陨,程序退出。