改變 Python 中線程執(zhí)行順序的方法
一、主線程會等待所有的子線程結(jié)束后才結(jié)束
首先我看下最普通情況下,主線程和子線程的情況。
import threading from time import sleep, ctime def sing(): for i in range(3): print("正在唱歌...%d" % i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d" % i) sleep(1) if __name__ == '__main__': print('---開始---:%s' % ctime()) t1 = threading.Thread(target=sing) t2 = threading.Thread(target=dance) t1.start() t2.start() print('---結(jié)束---:%s' % ctime())
運(yùn)行結(jié)果:
最后一行打印的代碼就算在一開始運(yùn)行了,程序也不會結(jié)束。
只有等待所有的子線程(sing 和 dance)都執(zhí)行完畢,主線程才會結(jié)束,即程序結(jié)束。
二、默認(rèn)狀態(tài)下,多線程的執(zhí)行順序是不確定的
我們先來看一段代碼:
import threading import time class MyThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) msg = "I'm "+self.name+' @ '+str(i) print(msg) def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test()
運(yùn)行結(jié)果:
I'm Thread-1 @ 0
I'm Thread-2 @ 0
I'm Thread-3 @ 0
I'm Thread-4 @ 0
I'm Thread-5 @ 0
I'm Thread-1 @ 1
I'm Thread-3 @ 1
I'm Thread-2 @ 1
I'm Thread-4 @ 1
I'm Thread-5 @ 1
I'm Thread-1 @ 2
I'm Thread-3 @ 2
I'm Thread-2 @ 2
I'm Thread-4 @ 2
I'm Thread-5 @ 2
每次的運(yùn)行結(jié)果可能都不一樣,但大體差不多。
說明:
從代碼和執(zhí)行結(jié)果我們可以看出,多線程程序的執(zhí)行順序是不確定的。
當(dāng)執(zhí)行到 sleep 語句時,線程將被阻塞,到 sleep 結(jié)束后,線程進(jìn)入就緒狀態(tài),等待調(diào)度,而線程調(diào)度將自行選擇一個線程執(zhí)行。
上面的代碼中只能保證每個線程都運(yùn)行完整個 run 函數(shù),但是線程的啟動順序、run 函數(shù)中每次循環(huán)的執(zhí)行順序都不能確定。
總結(jié)
每個線程默認(rèn)有一個名字,盡管上面的例子中沒有指定線程對象的 name,但是 python 會自動為線程指定一個名字。
當(dāng)線程的 run() 方法結(jié)束時該線程完成。
無法控制線程調(diào)度程序,但可以通過別的方式來影響線程調(diào)度的方式。
三、Python daemon 守護(hù)線程詳解
當(dāng)程序中擁有多個線程時,主線程執(zhí)行結(jié)束并不會影響子線程繼續(xù)執(zhí)行。
換句話說,只有程序中所有線程全部執(zhí)行完畢后,程序才算真正結(jié)束。
Python 還支持創(chuàng)建另一種線程,稱為守護(hù)線程(或后臺線程)。
此類線程的特點(diǎn)是,當(dāng)程序中主線程及所有非守護(hù)線程執(zhí)行結(jié)束時,未執(zhí)行完畢的守護(hù)線程也會隨之消亡,程序?qū)⒔Y(jié)束運(yùn)行。
守護(hù)線程本質(zhì)也是線程,因此其創(chuàng)建方式和普通線程一樣,唯一不同之處在于,將普通線程設(shè)為守護(hù)線程,需通過線程對象調(diào)用其 damon 屬性,將該屬性的值改為 True。
注意:線程對象調(diào)用 daemon 屬性必須在調(diào)用 start() 方法之前,否則 Python 解釋器將報(bào) RuntimeError 錯誤。
import threading def action(len): for i in range(len): print(threading.current_thread().getName() + "," + str(i)) def main(): t1 = threading.Thread(target=action, args=(10,)) # 設(shè)置子線程為守護(hù)進(jìn)程 t1.daemon = True t1.start() for i in range(3): print(threading.current_thread().getName()+','+str(i)) if __name__ == "__main__": main()
運(yùn)行結(jié)果:
Thread-1,0
MainThread,0
MainThread,1
MainThread,2
程序中,子線程里的程序就循環(huán)了一次,接著主線程執(zhí)行完后,子線程就不打印信息了。
由于該程序中除了守護(hù)線程就只有主線程,因此只要主線程執(zhí)行結(jié)束,則守護(hù)線程也隨之消亡。
四、控制線程執(zhí)行順序
通過前面的學(xué)習(xí)我們知道,主線程和子線程會輪流獲得 CPU 的資源。
但有時候,我們想讓某個子線程先執(zhí)行,然后再讓主線程執(zhí)行代碼,該如何實(shí)現(xiàn)呢?
很簡單,通過調(diào)用線程對象的 join() 方法即可。
join() 方法的功能是在程序指定位置,優(yōu)先讓該方法的調(diào)用者使用 CPU 資源。
該方法的語法格式如下:
thread.join( [timeout] )
timeout 參數(shù)作為可選參數(shù),其功能是指定 thread 線程最多可以霸占 CPU 資源的時間(以秒為單位)。
如果省略,則默認(rèn)直到 thread 執(zhí)行結(jié)束(進(jìn)入死亡狀態(tài))才釋放 CPU 資源。
我們?nèi)耘f拿上面的例子來舉例:
import threading def action(len): for i in range(len): print(threading.current_thread().getName() + "," + str(i)) def main(): t1 = threading.Thread(target=action, args=(10,)) # 設(shè)置子線程為守護(hù)進(jìn)程 t1.daemon = True t1.start() t1.join() for i in range(3): print(threading.current_thread().getName()+','+str(i)) if __name__ == "__main__": main()
我們在子線程調(diào)用的后面,添加了 t1.join()。
運(yùn)行結(jié)果:
Thread-1,0
Thread-1,1
Thread-1,2
Thread-1,3
Thread-1,4
Thread-1,5
Thread-1,6
Thread-1,7
Thread-1,8
Thread-1,9
MainThread,0
MainThread,1
MainThread,2
上面的例子中,t1 線程調(diào)用了 join() 方法,并且沒有指定具體的 timeout 參數(shù)值。
這意味著如果程序想繼續(xù)往下執(zhí)行,必須先執(zhí)行完 t1 子線程。
以上就是改變 Python 中線程的執(zhí)行順序的方法的詳細(xì)內(nèi)容,更多關(guān)于改變 Python 中線程的執(zhí)行順序的資料請關(guān)注腳本之家其它相關(guān)文章!
- 淺談Python3多線程之間的執(zhí)行順序問題
- python多線程實(shí)現(xiàn)同時執(zhí)行兩個while循環(huán)的操作
- python 實(shí)現(xiàn)兩個線程交替執(zhí)行
- 使用Python paramiko模塊利用多線程實(shí)現(xiàn)ssh并發(fā)執(zhí)行操作
- 詳解Python 多線程 Timer定時器/延遲執(zhí)行、Event事件
- python實(shí)現(xiàn)多線程的方式及多條命令并發(fā)執(zhí)行
- python多線程方式執(zhí)行多個bat代碼
- python使用裝飾器和線程限制函數(shù)執(zhí)行時間的方法
相關(guān)文章
python實(shí)現(xiàn)用于測試網(wǎng)站訪問速率的方法
這篇文章主要介紹了python實(shí)現(xiàn)用于測試網(wǎng)站訪問速率的方法,涉及Python中urllib2模塊及時間的相關(guān)操作技巧,需要的朋友可以參考下2015-05-05python 基于PYMYSQL使用MYSQL數(shù)據(jù)庫
這篇文章主要介紹了python 基于PYMYSQL使用MYSQL數(shù)據(jù)庫的方法,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-12-12使用Python-OpenCV消除圖像中孤立的小區(qū)域操作
這篇文章主要介紹了使用Python-OpenCV消除圖像中孤立的小區(qū)域操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07Python PyQt5運(yùn)行程序把輸出信息展示到GUI圖形界面上
這篇文章主要介紹了Python PyQt5運(yùn)行程序把輸出信息展示到GUI圖形界面上,本文通過截圖實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04pytorch numpy list類型之間的相互轉(zhuǎn)換實(shí)例
今天小編就為大家分享一篇pytorch numpy list類型之間的相互轉(zhuǎn)換實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08Python中的np.argmin()和np.argmax()函數(shù)用法
這篇文章主要介紹了Python中的np.argmin()和np.argmax()函數(shù)用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06NumPy數(shù)組創(chuàng)建方法與索引訪問詳解
這篇文章主要介紹了NumPy數(shù)組創(chuàng)建方法與索引訪問,NumPy 中的核心數(shù)據(jù)結(jié)構(gòu)是 ndarray,它代表多維數(shù)組,NumPy 提供了多種方法來創(chuàng)建 ndarray 對象,文中通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-05-05numpy.ndarray 交換多維數(shù)組(矩陣)的行/列方法
今天小編就為大家分享一篇numpy.ndarray 交換多維數(shù)組(矩陣)的行/列方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08