Python多線程原理與用法詳解
本文實例講述了Python多線程原理與用法。分享給大家供大家參考,具體如下:
多線程(英語:multithreading),是指從軟件或者硬件上實現多個線程并發(fā)執(zhí)行的技術。具有多線程能力的計算機因有硬件支持而能夠在同一時間執(zhí)行多于一個線程,進而提升整體處理性能。具有這種能力的系統(tǒng)包括對稱多處理機、多核心處理器以及芯片級多處理(Chip-level multithreading)或同時多線程(Simultaneous multithreading)處理器。[1] 在一個程序中,這些獨立運行的程序片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理(Multithreading)”。具有多線程能力的計算機因有硬件支持而能夠在同一時間執(zhí)行多于一個線程(臺灣譯作“執(zhí)行緒”),進而提升整體處理性能。
創(chuàng)建并啟動一個線程
import threading
def runtask(name):
print("%s線程已啟動"%name)
t = threading.Thread(target=runtask,args=("task1",)) # args因為是一個元組,所以必須這樣寫,否則運行將報錯
t.start()
join
等待當前線程執(zhí)行完畢
import threading
import time
def runtask(name):
print("%s線程已啟動"%name)
time.sleep(2)
t = threading.Thread(target=runtask,args=("task1",))
t.start()
t.join()
print("abc") # 過了2s才會打印,若無等待將看不到等待2s的效果
setDaemon(True)
將線程設置為守護線程。若設置為守護線程,主線程結束后,子線程也將結束,并且主線程不會理會子線程是否結束,主線程不會等待子線程結束完后才結束。若沒有設置為守護線程,主線程會等待子線程結束后才會結束。
active_count
程序的線程數量,數量=主線程+子線程數量
Lock(互斥鎖)
Python編程中,引入了對象互斥鎖的概念,來保證共享數據操作的完整性。每個對象都對應于一個可稱為” 互斥鎖” 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。在Python中我們使用threading模塊提供的Lock類。
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()
上面這段代碼如果沒有加上互斥鎖,在Python2.x中執(zhí)行的結果將會是亂的。在Python3.x中執(zhí)行卻總是正確的,似乎是自動為其加了鎖
RLock(遞歸鎖,可重入鎖)
當一個線程中遇到鎖嵌套情況該怎么辦,又會遇到什么情況?
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()
這是一個很簡單的線程鎖死案例,程序將被卡死,停止不動。為了解決這一情況,Python提供了遞歸鎖RLock(可重入鎖)。這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的代碼只需做一些小小的改動
lock = threading.Lock()
修改為:
lock = threading.RLock()
那么程序將不會發(fā)生死鎖情況。
最大可執(zhí)行線程
threading.BoundedSemaphore(5)設置可同時執(zhí)行的最大線程數為5個,后面的線程需排隊等待前面的線程執(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個線程在同時運行,其他線程需等待前面的線程執(zhí)行完畢,這就是最大可執(zhí)行線程。
Event
Python提供了Event對象用于線程間通信,它是由線程設置的信號標志,如果信號標志位為假,則線程等待直到信號被其他線程設置成真。Event中提供了四個重要的方法來滿足基本的需求。
- - clear:清除標記
- - set:設置標記
- - is_set:是否被標記
- - wait:等待被標記
代碼示例:
import threading,time
def lighter():
num = 0
event.set() # 設置標記
while True:
if num >= 5 and num < 10:
event.clear() # 清除標記
print("紅燈亮起,車輛禁止通行")
if num >= 10:
event.set() # 設置標記
print("綠燈亮起,車輛可以通行")
num = 0
num += 1
time.sleep(1)
def car():
while True:
if event.is_set():
print("車輛正在跑...")
else:
print("車輛停下了")
event.wait()
time.sleep(1)
event = threading.Event()
t1 = threading.Thread(target=lighter,)
t2 = threading.Thread(target=car,)
t1.start()
t2.start()
這是一個簡單的紅燈停綠燈行案例。初始設置為綠燈并標記,車輛看到標記后通行,當紅燈亮起的時候取消標記,車輛看到沒有標記時停下,等待標記。
Queue隊列
使任務按照某一種特定順序有條不紊的進行。下面介紹幾種常用的隊列:
- -
queue.Queue():先進先出 - -
queue.LifoQueue():先進后出 - -
queue.PriorityQueue:優(yōu)先級隊列,優(yōu)先級的值越小,越先執(zhí)行
下面介紹幾種常用的方法:
- -
get():獲取item,如果隊列已經取空將會卡住??稍O置timeout參數,給定一個超時的值,或者設置參數block=False,隊列空直接拋異常 - -
get_nowait():b獲取item。如果隊列取空了,將會直接拋異常 - -
put():放入隊列 - -
empty():隊列是否為空 - -
qsize():獲取隊列的item數量
更多關于Python相關內容感興趣的讀者可查看本站專題:《Python進程與線程操作技巧總結》、《Python數據結構與算法教程》、《Python函數使用技巧總結》、《Python字符串操作技巧匯總》、《Python入門與進階經典教程》、《Python+MySQL數據庫程序設計入門教程》及《Python常見數據庫操作技巧匯總》
希望本文所述對大家Python程序設計有所幫助。
相關文章
python利用pandas將excel文件轉換為txt文件的方法
今天小編就為大家分享一篇python利用pandas將excel文件轉換為txt文件的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
Django通過dwebsocket實現websocket的例子
今天小編就為大家分享一篇Django通過dwebsocket實現websocket的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11

