日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python 多线程中的 join 和 daemon

發(fā)布時(shí)間:2025/3/15 python 8 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 多线程中的 join 和 daemon 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 第一關(guān):簡單的 join()
    • 第二關(guān):join(timeout)
    • 第三關(guān):setDaemon(True)

第一關(guān):簡單的 join()

import threading import timedef run():time.sleep(2)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(2)if __name__ == '__main__':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()start_time = time.time()thread_list[0].join()print('一共用時(shí):', time.time() - start_time)print('主線程結(jié)束!', threading.current_thread().name)

執(zhí)行結(jié)果是:

這是主線程: MainThread 當(dāng)前線程的名字是: Thread-1 當(dāng)前線程的名字是: Thread-5當(dāng)前線程的名字是: Thread-4當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-2 Thread-3 一共用時(shí): 4.014104843139648 主線程結(jié)束! MainThread

為了弄清楚 join() 的作用,我關(guān)注代碼 23 行的用時(shí)。

第 23 行,主線程阻塞,直到 thread_list[0] 退出后才往下執(zhí)行。

看打印結(jié)果第 7 行,用時(shí) 4s,這是好理解的,因?yàn)?thread_list[0] 大概用 4s。說明主線程確實(shí)阻塞了,一直阻塞到 thread_list[0] 執(zhí)行完畢。

我們把代碼修改一下,把 run() 函數(shù)的 sleep 時(shí)間增加。

def run():time.sleep(5)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(5)

預(yù)期結(jié)果是主線稱大約阻塞 10s

執(zhí)行結(jié)果是:

這是主線程: MainThread 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-5當(dāng)前線程的名字是: Thread-1當(dāng)前線程的名字是: Thread-3 當(dāng)前線程的名字是: Thread-2Thread-4一共用時(shí): 10.009864091873169 主線程結(jié)束! MainThread

和預(yù)期相符。

如果把 run 函數(shù)改成死循環(huán),比如

def run():while(True):time.sleep(2)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(2)

那么主線程就會(huì)一直阻塞,根本不會(huì)打印 “一共用時(shí):…”,而是一直打印 “當(dāng)前線程的名字是:…”

這也印證了主線程確實(shí)阻塞了,等待子線程退出,如果不退出就一直阻塞。

第二關(guān):join(timeout)

在上面的例子中,如果子線程不返回,父線程就一直阻塞。如果需求是父線程阻塞一段時(shí)間,時(shí)間到了以后,就算子線程不返回,父線程也可以繼續(xù)向下執(zhí)行,那么我們可以給 join() 傳入一個(gè)時(shí)間參數(shù)。意思是最多等待這么多,等不到我就繼續(xù)往下執(zhí)行了。

實(shí)驗(yàn)代碼是:

import threading import timedef run():time.sleep(2)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(2)if __name__ == '__main__':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()start_time = time.time()thread_list[0].join(2)print('一共用時(shí):', time.time() - start_time)print('主線程結(jié)束!', threading.current_thread().name)

第 23 行:父線程最多等待 2s,等不到就繼續(xù)執(zhí)行

打印結(jié)果是:

這是主線程: MainThread 一共用時(shí): 2.0001044273376465 主線程結(jié)束! MainThread 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-2 Thread-3 Thread-1 當(dāng)前線程的名字是: Thread-4 當(dāng)前線程的名字是: Thread-5

可以看到,父線程確實(shí)只阻塞了 2s。需要強(qiáng)調(diào)的是,主線程阻塞,不會(huì)對(duì)子線程造成任何影響,子線程依然執(zhí)行自己的代碼,根本不存在什么“主線程等待一段時(shí)間然后殺死子線程”,這是謬論。

當(dāng)然,如果你傳入?yún)?shù)是 10,主線程不一定非要等 10s,如果子線程執(zhí)行了 3s 就返回了,那么主線程會(huì)立刻往下執(zhí)行,而不是繼續(xù)等待 7s。

例如把代碼第 23 行改成

thread_list[0].join(6)

執(zhí)行結(jié)果是:

這是主線程: MainThread 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-2 Thread-3當(dāng)前線程的名字是: 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-1Thread-4 Thread-5 一共用時(shí): 4.028920888900757 主線程結(jié)束! MainThread

第三關(guān):setDaemon(True)

先上代碼:

import threading import timedef run():time.sleep(2)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(2)if __name__ == '__main__':print('這是主線程:', threading.current_thread().name)thread_list = []for i in range(5):t = threading.Thread(target=run)t.setDaemon(True)thread_list.append(t)for t in thread_list:t.start()start_time = time.time()print('一共用時(shí):', time.time() - start_time)print('主線程結(jié)束!', threading.current_thread().name)

和之前不一樣的是第 17 行,多加了 t.setDaemon(True),這句話的意思是把線程的 daemon 屬性設(shè)成 True。daemon 有守護(hù)神的意思,也可以說把 t 設(shè)置為守護(hù)線程,守護(hù)誰呢?守護(hù)父線程嗎?咱們后面會(huì)分析。

網(wǎng)上充斥著這樣的解釋:如果一個(gè)子線程的 daemon 被設(shè)為 True,那么父線程結(jié)束了,這個(gè)子線程就立刻被干掉。是不是這樣呢?我們看執(zhí)行結(jié)果:

這是主線程: MainThread 一共用時(shí): 0.0 主線程結(jié)束! MainThread

似乎是這樣,主線程一執(zhí)行完,子線程就被殺死了,連打印都來不及。

我們把 15-18 行代碼改一下:

for i in range(5):t = threading.Thread(target=run)# t.setDaemon(True)thread_list.append(t)thread_list[0].setDaemon(True)

也就是說,僅僅設(shè)置 thread_list[0] 的 daemon 為 True。預(yù)期結(jié)果是主線程一結(jié)束,thread_list[0] 就被殺死了,其余的子線程會(huì)繼續(xù)執(zhí)行。

結(jié)果是:

這是主線程: MainThread 一共用時(shí): 0.0 主線程結(jié)束! MainThread 當(dāng)前線程的名字是: Thread-3當(dāng)前線程的名字是: Thread-2當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-5 當(dāng)前線程的名字是: Thread-4Thread-1

這就奇怪了,不是 Thread-1 被殺死了嗎,怎么后面還有打印呢?

肯定是我們的理解有問題。實(shí)際上,官方是這樣解釋 daemon 的:

A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left.

以上摘自 https://docs.python.org/3/library/threading.html,黑體字是我加的。

也就是說,如果父線程執(zhí)行完畢,剩下的都是守護(hù)線程,那么這些守護(hù)線程也不用再執(zhí)行了,直接強(qiáng)制退出;如果父線程執(zhí)行完畢,剩下了 3 個(gè)守護(hù)線程和 1 個(gè)非守護(hù)線程,那么這 3 個(gè)守護(hù)線程還會(huì)繼續(xù)執(zhí)行,當(dāng)非守護(hù)線程結(jié)束的時(shí)候,這些守護(hù)線程才會(huì)強(qiáng)制退出。

我們做個(gè)實(shí)驗(yàn):

import threading import timedef run(cnt):while cnt:time.sleep(1)print('當(dāng)前線程的名字是: ', threading.current_thread().name)time.sleep(1)cnt = cnt - 1print(threading.current_thread().name, ' 退出')if __name__ == '__main__':print('這是主線程:', threading.current_thread().name)thread_list = []cnt_list = [2, 4, 4, 4, 4]for i in range(5):t = threading.Thread(target=run, args=(cnt_list[i],))t.setDaemon(True)thread_list.append(t)thread_list[0].setDaemon(False)for t in thread_list:t.start()start_time = time.time()print('一共用時(shí):', time.time() - start_time)print('主線程結(jié)束!', threading.current_thread().name)

5-11:每個(gè)子線程執(zhí)行時(shí)間不一樣,根據(jù)傳參 cnt 定

第 16 行,增加了cnt_list = [2, 4, 4, 4, 4],意圖是讓 thread_list[0] 執(zhí)行時(shí)間短一些,僅執(zhí)行 while 循環(huán) 2 次,其他子線程執(zhí)行 4 次

18-23:先把所有子線程設(shè)為守護(hù)線程,后面再把 thread_list[0] 設(shè)為非守護(hù)線程(偷懶了)

輸出結(jié)果:

這是主線程: MainThread 一共用時(shí): 0.0 主線程結(jié)束! MainThread 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-5 當(dāng)前線程的名字是: Thread-2 Thread-1 Thread-4 當(dāng)前線程的名字是: Thread-3 當(dāng)前線程的名字是: Thread-1當(dāng)前線程的名字是: 當(dāng)前線程的名字是: 當(dāng)前線程的名字是: Thread-3 當(dāng)前線程的名字是: Thread-5Thread-4 Thread-2Thread-1 退出

可以發(fā)現(xiàn),父線程退出后,守護(hù)線程并沒有退出,當(dāng)非守護(hù)線程 Thread-1 退出后,其他守護(hù)線程強(qiáng)制退出。

由此可見,守護(hù)線程不僅僅守護(hù)父線程,也會(huì)守護(hù)其他非守護(hù)線程。

以上就是本文的全部內(nèi)容。歡迎各位老師批評(píng)斧正。

總結(jié)

以上是生活随笔為你收集整理的python 多线程中的 join 和 daemon的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。