Python多線程原理與用法詳解
本文實(shí)例講述了Python多線程原理與用法。分享給大家供大家參考,具體如下:
多線程(英語(yǔ):multithreading),是指從軟件或者硬件上實(shí)現(xiàn)多個(gè)線程并發(fā)執(zhí)行的技術(shù)。具有多線程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多于一個(gè)線程,進(jìn)而提升整體處理性能。具有這種能力的系統(tǒng)包括對(duì)稱(chēng)多處理機(jī)、多核心處理器以及芯片級(jí)多處理(Chip-level multithreading)或同時(shí)多線程(Simultaneous multithreading)處理器。[1] 在一個(gè)程序中,這些獨(dú)立運(yùn)行的程序片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理(Multithreading)”。具有多線程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多于一個(gè)線程(臺(tái)灣譯作“執(zhí)行緒”),進(jìn)而提升整體處理性能。
創(chuàng)建并啟動(dòng)一個(gè)線程
import threading
def runtask(name):
print("%s線程已啟動(dòng)"%name)
t = threading.Thread(target=runtask,args=("task1",)) # args因?yàn)槭且粋€(gè)元組,所以必須這樣寫(xiě),否則運(yùn)行將報(bào)錯(cuò)
t.start()
join
等待當(dāng)前線程執(zhí)行完畢
import threading
import time
def runtask(name):
print("%s線程已啟動(dòng)"%name)
time.sleep(2)
t = threading.Thread(target=runtask,args=("task1",))
t.start()
t.join()
print("abc") # 過(guò)了2s才會(huì)打印,若無(wú)等待將看不到等待2s的效果
setDaemon(True)
將線程設(shè)置為守護(hù)線程。若設(shè)置為守護(hù)線程,主線程結(jié)束后,子線程也將結(jié)束,并且主線程不會(huì)理會(huì)子線程是否結(jié)束,主線程不會(huì)等待子線程結(jié)束完后才結(jié)束。若沒(méi)有設(shè)置為守護(hù)線程,主線程會(huì)等待子線程結(jié)束后才會(huì)結(jié)束。
active_count
程序的線程數(shù)量,數(shù)量=主線程+子線程數(shù)量
Lock(互斥鎖)
Python編程中,引入了對(duì)象互斥鎖的概念,來(lái)保證共享數(shù)據(jù)操作的完整性。每個(gè)對(duì)象都對(duì)應(yīng)于一個(gè)可稱(chēng)為” 互斥鎖” 的標(biāo)記,這個(gè)標(biāo)記用來(lái)保證在任一時(shí)刻,只能有一個(gè)線程訪問(wèn)該對(duì)象。在Python中我們使用threading模塊提供的Lock類(lèi)。
import threading,time
def runtask(name):
global count
time.sleep(1)
lock.acquire() # 獲取鎖資源,并返回是否獲取成功
count+=1
print(name,count)
lock.release() # 釋放資源
count = 0
lock = threading.Lock() # 互斥鎖
for index in range(50):
t = threading.Thread(target=runtask,args=("thread%d"%index,))
t.start()
上面這段代碼如果沒(méi)有加上互斥鎖,在Python2.x中執(zhí)行的結(jié)果將會(huì)是亂的。在Python3.x中執(zhí)行卻總是正確的,似乎是自動(dòng)為其加了鎖
RLock(遞歸鎖,可重入鎖)
當(dāng)一個(gè)線程中遇到鎖嵌套情況該怎么辦,又會(huì)遇到什么情況?
def run1():
global count1
lock.acquire()
count1 += 1
lock.release()
return count1
def run2():
global count2
lock.acquire()
count2 += 1
lock.release()
return count2
def runtask():
lock.acquire()
r1 = run1()
print("="*30)
r2 = run2()
lock.release()
print(r1,r2)
count1,count2 = 0,0
lock = threading.Lock()
for index in range(50):
t = threading.Thread(target=runtask,)
t.start()
這是一個(gè)很簡(jiǎn)單的線程鎖死案例,程序?qū)⒈豢ㄋ?,停止不?dòng)。為了解決這一情況,Python提供了遞歸鎖RLock(可重入鎖)。這個(gè)RLock內(nèi)部維護(hù)著一個(gè)Lock和一個(gè)counter變量,counter記錄了acquire的次數(shù),從而使得資源可以被多次require。直到一個(gè)線程所有的acquire都被release,其他的線程才能獲得資源。上面的代碼只需做一些小小的改動(dòng)
lock = threading.Lock()
修改為:
lock = threading.RLock()
那么程序?qū)⒉粫?huì)發(fā)生死鎖情況。
最大可執(zhí)行線程
threading.BoundedSemaphore(5)設(shè)置可同時(shí)執(zhí)行的最大線程數(shù)為5個(gè),后面的線程需排隊(duì)等待前面的線程執(zhí)行完畢
import time,threading
def runtask(name):
global num
semaphore.acquire()
time.sleep(1)
num += 1
semaphore.release()
print(name,num)
num = 0
semaphore = threading.BoundedSemaphore(5)
for index in range(50):
t = threading.Thread(target=runtask,args=("線程%s"%index,))
t.start()
執(zhí)行效果:

可以看出上面的程序是每次只有5個(gè)線程在同時(shí)運(yùn)行,其他線程需等待前面的線程執(zhí)行完畢,這就是最大可執(zhí)行線程。
Event
Python提供了Event對(duì)象用于線程間通信,它是由線程設(shè)置的信號(hào)標(biāo)志,如果信號(hào)標(biāo)志位為假,則線程等待直到信號(hào)被其他線程設(shè)置成真。Event中提供了四個(gè)重要的方法來(lái)滿足基本的需求。
- - clear:清除標(biāo)記
- - set:設(shè)置標(biāo)記
- - is_set:是否被標(biāo)記
- - wait:等待被標(biāo)記
代碼示例:
import threading,time
def lighter():
num = 0
event.set() # 設(shè)置標(biāo)記
while True:
if num >= 5 and num < 10:
event.clear() # 清除標(biāo)記
print("紅燈亮起,車(chē)輛禁止通行")
if num >= 10:
event.set() # 設(shè)置標(biāo)記
print("綠燈亮起,車(chē)輛可以通行")
num = 0
num += 1
time.sleep(1)
def car():
while True:
if event.is_set():
print("車(chē)輛正在跑...")
else:
print("車(chē)輛停下了")
event.wait()
time.sleep(1)
event = threading.Event()
t1 = threading.Thread(target=lighter,)
t2 = threading.Thread(target=car,)
t1.start()
t2.start()
這是一個(gè)簡(jiǎn)單的紅燈停綠燈行案例。初始設(shè)置為綠燈并標(biāo)記,車(chē)輛看到標(biāo)記后通行,當(dāng)紅燈亮起的時(shí)候取消標(biāo)記,車(chē)輛看到?jīng)]有標(biāo)記時(shí)停下,等待標(biāo)記。
Queue隊(duì)列
使任務(wù)按照某一種特定順序有條不紊的進(jìn)行。下面介紹幾種常用的隊(duì)列:
- -
queue.Queue():先進(jìn)先出 - -
queue.LifoQueue():先進(jìn)后出 - -
queue.PriorityQueue:優(yōu)先級(jí)隊(duì)列,優(yōu)先級(jí)的值越小,越先執(zhí)行
下面介紹幾種常用的方法:
- -
get():獲取item,如果隊(duì)列已經(jīng)取空將會(huì)卡住。可設(shè)置timeout參數(shù),給定一個(gè)超時(shí)的值,或者設(shè)置參數(shù)block=False,隊(duì)列空直接拋異常 - -
get_nowait():b獲取item。如果隊(duì)列取空了,將會(huì)直接拋異常 - -
put():放入隊(duì)列 - -
empty():隊(duì)列是否為空 - -
qsize():獲取隊(duì)列的item數(shù)量
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Python進(jìn)程與線程操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門(mén)與進(jìn)階經(jīng)典教程》、《Python+MySQL數(shù)據(jù)庫(kù)程序設(shè)計(jì)入門(mén)教程》及《Python常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
python-opencv中的cv2.inRange函數(shù)用法說(shuō)明
這篇文章主要介紹了python-opencv中的cv2.inRange函數(shù)用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
Python 生成一個(gè)從0到n個(gè)數(shù)字的列表4種方法小結(jié)
今天小編就為大家分享一篇Python 生成一個(gè)從0到n個(gè)數(shù)字的列表4種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
使用Python實(shí)現(xiàn)炫酷的數(shù)據(jù)動(dòng)態(tài)圖大全
數(shù)據(jù)可視化是通過(guò)圖形、圖表、地圖等可視元素將數(shù)據(jù)呈現(xiàn)出來(lái),以便更容易理解、分析和解釋,它是將抽象的數(shù)據(jù)轉(zhuǎn)化為直觀形象的過(guò)程,本文給大家介紹了使用Python實(shí)現(xiàn)炫酷的數(shù)據(jù)動(dòng)態(tài)圖大全,需要的朋友可以參考下2024-06-06
Python使用bcrypt?或?Passlib?對(duì)系統(tǒng)用戶密碼進(jìn)行哈希和驗(yàn)證處理操作
在Python?開(kāi)發(fā)中,我們可以引入bcrypt?或?Passlib?對(duì)系統(tǒng)用戶密碼進(jìn)行哈希和驗(yàn)證處理,以及介紹使用其他類(lèi)庫(kù)實(shí)現(xiàn)常規(guī)加解密處理操作,需要的朋友可以參考下2024-08-08
如何獲取Python簡(jiǎn)單for循環(huán)索引
這篇文章主要介紹了如何獲取Python簡(jiǎn)單for循環(huán)索引,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Python測(cè)試線程應(yīng)用程序過(guò)程解析
這篇文章主要介紹了Python測(cè)試線程應(yīng)用程序過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Python 標(biāo)準(zhǔn)庫(kù)time時(shí)間的訪問(wèn)和轉(zhuǎn)換問(wèn)題小結(jié)
time 模塊為 Python 提供了處理時(shí)間和日期的多種功能,適用于多種與時(shí)間相關(guān)的場(chǎng)景,包括獲取當(dāng)前時(shí)間、格式化時(shí)間、暫停程序執(zhí)行、計(jì)算程序運(yùn)行時(shí)長(zhǎng)等,這篇文章主要介紹了Python 標(biāo)準(zhǔn)庫(kù)time時(shí)間的訪問(wèn)和轉(zhuǎn)換,需要的朋友可以參考下2025-01-01
Python網(wǎng)絡(luò)編程實(shí)戰(zhàn)之爬蟲(chóng)技術(shù)入門(mén)與實(shí)踐
這篇文章主要介紹了Python網(wǎng)絡(luò)編程實(shí)戰(zhàn)之爬蟲(chóng)技術(shù)入門(mén)與實(shí)踐,了解這些基礎(chǔ)概念和原理將幫助您更好地理解網(wǎng)絡(luò)爬蟲(chóng)的實(shí)現(xiàn)過(guò)程和技巧,需要的朋友可以參考下2023-04-04
PyTorch中的方法torch.randperm()示例介紹
在 PyTorch 中,torch.randperm(n) 函數(shù)用于生成一個(gè)從 0 到 n-1 的隨機(jī)排列的整數(shù)序列,這篇文章主要介紹了PyTorch中的方法torch.randperm()介紹,需要的朋友可以參考下2024-05-05

