詳解python中的線程
Python中創(chuàng)建線程有兩種方式:函數(shù)或者用類來(lái)創(chuàng)建線程對(duì)象。
函數(shù)式:調(diào)用 _thread 模塊中的start_new_thread()函數(shù)來(lái)產(chǎn)生新線程。
類:創(chuàng)建threading.Thread的子類來(lái)包裝一個(gè)線程對(duì)象。
1.線程的創(chuàng)建
1.1 通過(guò)thread類直接創(chuàng)建
import threading import time def foo(n): time.sleep(n) print("foo func:",n) def bar(n): time.sleep(n) print("bar func:",n) s1=time.time() #創(chuàng)建一個(gè)線程實(shí)例t1,foo為這個(gè)線程要運(yùn)行的函數(shù) t1=threading.Thread(target=foo,args=(3,)) t1.start() #啟動(dòng)線程t1 #創(chuàng)建一個(gè)線程實(shí)例t2,bar為這個(gè)線程要運(yùn)行的函數(shù) t2=threading.Thread(target=bar,args=(5,)) t2.start() #啟動(dòng)線程t2 print("ending") s2=time.time() print("cost time:",s2-s1)
在這段程序里,一個(gè)函數(shù)會(huì)先休眠幾秒鐘,然后再打印一句話,第二個(gè)函數(shù)也是先休眠幾秒鐘,然后打印一句話。
接著程序會(huì)實(shí)例化兩個(gè)線程,并調(diào)用兩個(gè)函數(shù)來(lái)執(zhí)行,最后會(huì)打印程序問(wèn)總共執(zhí)行了多少時(shí)間
程序運(yùn)行結(jié)果如下:
ending cost time: 0.002000093460083008 foo func: 3 bar func: 5
程序會(huì)先運(yùn)行父線程,打印"ending",然后打印程序執(zhí)行父線程的時(shí)間,最后才會(huì)運(yùn)行子線程
1.2 通過(guò)thread類來(lái)繼承式創(chuàng)建
import threading import time # 定義MyThread類,其繼承自threading.Thread這個(gè)父類 class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): print("ok") time.sleep(2) print("end t1") # 對(duì)類進(jìn)行實(shí)例化 t1=MyThread() # 啟動(dòng)線程 t1.start() print("ending")
2. Thread類的一些常用方法
2.1 join():在子線程完成之前,主線程將一直被阻塞****
線程的join方法必須在子線程的start方法之后定義
在第一個(gè)例子中加入兩行代碼,如下:
import threading import time def foo(n): time.sleep(n) print("foo func:",n) def bar(n): time.sleep(n) print("bar func:",n) s1=time.time() t1=threading.Thread(target=foo,args=(3,)) t1.start() t2=threading.Thread(target=bar,args=(5,)) t2.start() t1.join() # 阻塞t1線程 t2.join() # 阻塞t2線程 print("ending") s2=time.time() print("cost time:",s2-s1)
再次執(zhí)行程序,運(yùn)行結(jié)果如下:
foo func: 3 bar func: 5 ending cost time: 5.002285957336426
程序運(yùn)行到子線程t1中的foo方法時(shí)會(huì)睡眠3秒鐘,與此同時(shí),子線程t2也在睡眠
等到子線程t1睡眠完成后,開(kāi)始打印foo函數(shù)中的print語(yǔ)句,然后子線程t1執(zhí)行完成
2秒鐘之后,子線程t2睡眠完成,開(kāi)始打印bar函數(shù)中的print語(yǔ)句,然后子線程t2也執(zhí)行完成。
而在這之前,主線程一直處于阻塞狀態(tài)。等到子線程執(zhí)行完成之后主線程才會(huì)執(zhí)行
2.2 setDeamon(True)
setDaemon方法作用是將進(jìn)程聲明為守護(hù)線程,必須在`start()`方法調(diào)用之前,
如果不設(shè)置為守護(hù)線程,程序會(huì)被無(wú)限掛起
在程序執(zhí)行過(guò)程中,執(zhí)行一個(gè)主線程,主線程又創(chuàng)建一個(gè)子線程時(shí),主線程和子線程會(huì)分別運(yùn)行。
當(dāng)主線程運(yùn)行完成時(shí),會(huì)檢驗(yàn)子線程是否執(zhí)行完成,如果子線程執(zhí)行完成,則主線程會(huì)等待子線程完成后再退出。
但是有的時(shí)候只要主線程執(zhí)行完成之后,不管子線程是否執(zhí)行完成,都和主線程一起退出,這個(gè)就需要調(diào)用setDeamon方法了。
拿第一個(gè)例子來(lái)說(shuō)吧,現(xiàn)在我想讓子線程t1和t2隨同主線程關(guān)閉,代碼如下:
import threading import time def foo(n): print("foo start") time.sleep(n) print("foo end...") def bar(n): print("bar start") time.sleep(n) print("bar end...") s1 = time.time() t1 = threading.Thread(target=foo, args=(3,)) t1.setDaemon(True) t1.start() t2 = threading.Thread(target=bar, args=(5,)) t2.setDaemon(True) t2.start() print("ending") s2 = time.time() print("cost time:", s2 - s1)
程序運(yùn)行結(jié)果如下 :
foo start bar start ending cost time: 0.003000020980834961
可以看到,把t1和t2都聲明為守護(hù)線程后,程序自上而下執(zhí)行,先執(zhí)行子線程t1中的foo方法,打印foo函數(shù)中的第一條打印語(yǔ)句,然后子線程t1進(jìn)入到睡眠狀態(tài)。
然后子線程t2執(zhí)行,打印bar函數(shù)中的第一條print語(yǔ)句,然后子線程t2進(jìn)入睡眠狀態(tài),程序切換到主線程運(yùn)行
主線程打印完"ending"語(yǔ)句,發(fā)現(xiàn)子線程t1和t2已經(jīng)被設(shè)置為守護(hù)線程,所以主線程不需要再等待兩個(gè)子線程執(zhí)行完成,而是立即結(jié)束,打印整個(gè)程序的執(zhí)行時(shí)間。
整個(gè)程序就跟隨主線程一起關(guān)閉了。
2.3 子線程的一些其他方法
isAlive() #判斷一個(gè)線程是否是活動(dòng)線程 getName() #返回線程的名字 setName() #設(shè)置線程的名字 import threading import time def foo(n): time.sleep(n) print("foo func:", n) def bar(n): time.sleep(n) print("bar func:", n) s1 = time.time() t1 = threading.Thread(target=foo, args=(3,)) t1.setDaemon(True) print("線程還未啟動(dòng)時(shí),判斷t1是否是活動(dòng)的線程:", t1.isAlive()) # 線程還未啟動(dòng),所以是False t1.start() # 啟動(dòng)線程 print("線程已啟動(dòng)時(shí),判斷t1是否是活動(dòng)的線程:", t1.isAlive()) # 線程已啟動(dòng),所以是True print("修改前的線程名為:",t1.getName()) # 獲取線程名 t1.setName("t1") #設(shè)置線程名 print("修改后的線程名為:",t1.getName()) # 獲取線程名 t1.join() print("線程執(zhí)行完成時(shí),判斷t1是不否是活動(dòng)的線程:", t1.isAlive()) # 線程已執(zhí)行完成,所以是False # print(threading.activeCount()) print("ending") s2 = time.time() print("cost time:", s2 - s1)
程序執(zhí)行結(jié)果:
線程還未啟動(dòng)時(shí),判斷t1是否是活動(dòng)的線程: False
線程已啟動(dòng)時(shí),判斷t1是否是活動(dòng)的線程: True
修改前的線程名為: Thread-1
修改后的線程名為: t1
foo func: 3
線程執(zhí)行完成時(shí),判斷t1是不否是活動(dòng)的線程: False
ending
cost time: 3.001171588897705
3.threading模塊提供的一些方法
threading.currentThread() #返回當(dāng)前的線程變量 threading.enumerate() #返回一個(gè)包含正在運(yùn)行的線程的列表,不包括啟動(dòng)前和終止后的線程 threading.activeCount() #返回正在運(yùn)行的線程數(shù)量,等同于len(threading.enumerate()) import threading import time def foo(n): time.sleep(n) print("foo func:", n) def bar(n): time.sleep(n) print("bar func:", n) s1 = time.time() t1 = threading.Thread(target=foo, args=(3,)) t1.setDaemon(True) t1.start() t2 = threading.Thread(target=bar, args=(5,)) t2.setDaemon(True) t2.start() print("程序中正在運(yùn)行的線程數(shù)量:",threading.activeCount()) print("程序中當(dāng)前的線程變量:",threading.currentThread()) print("當(dāng)前正在運(yùn)行的線程的列表:",threading.enumerate()) print("ending") s2 = time.time() print("cost time:", s2 - s1)
程序執(zhí)行結(jié)果:
程序中正在運(yùn)行的線程數(shù)量: 3
程序中當(dāng)前的線程變量: <_MainThread(MainThread, started 7064)>
當(dāng)前正在運(yùn)行的線程的列表: [<_MainThread(MainThread, started 7064)>, <Thread(Thread-1, started daemon 6384)>, <Thread(Thread-2, started daemon 2640)>]
ending
cost time: 0.002000093460083008
總結(jié)
以上所述是小編給大家介紹的詳解python中的線程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Python使用try except處理程序異常的三種常用方法分析
這篇文章主要介紹了Python使用try except處理程序異常的三種常用方法,結(jié)合實(shí)例形式分析了Python基于try except語(yǔ)句針對(duì)異常的捕獲、查看、回溯等相關(guān)操作技巧,需要的朋友可以參考下2018-09-09pytorch 實(shí)現(xiàn)在測(cè)試的時(shí)候啟用dropout
這篇文章主要介紹了pytorch 實(shí)現(xiàn)在測(cè)試的時(shí)候啟用dropout的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05Python元組操作實(shí)例分析【創(chuàng)建、賦值、更新、刪除等】
這篇文章主要介紹了Python元組操作方法,結(jié)合具體實(shí)例形式分析了Python中元組的創(chuàng)建、賦值、更新、刪除等操作實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07使用pandas實(shí)現(xiàn)csv/excel sheet互相轉(zhuǎn)換的方法
今天小編就為大家分享一篇使用pandas實(shí)現(xiàn)csv/excel sheet互相轉(zhuǎn)換的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12Flask傳遞URL參數(shù)的實(shí)現(xiàn)
在Flask中,傳遞URL參數(shù)是一種常見(jiàn)且強(qiáng)大的功能,本文主要介紹了Flask傳遞URL參數(shù)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-09-09