一、執行緒模組
Python3 透過兩個標準庫 _thread 和 threading 提供對執行緒的支援。
_thread 提供了低階別的、原始的執行緒以及一個簡單的鎖,它相比於 threading 模組的功能還是比較有限的。
threading 模組除了包含 _thread 模組中的所有方法外,還提供的其他方法:
- threading.currentThread(): 返回當前的執行緒變數。
- threading.enumerate(): 返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
- threading.activeCount(): 返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。
除了使用方法外,執行緒模組同樣提供了Thread類來處理執行緒,Thread類提供了以下方法:
- run(): 用以表示執行緒活動的方法。
- start():啟動執行緒活動。
- join([time]): 等待至執行緒中止。這阻塞呼叫執行緒直至執行緒的join() 方法被呼叫中止-正常退出或者丟擲未處理的異常-或者是可選的超時發生。
- isAlive(): 返回執行緒是否活動的。
- getName(): 返回執行緒名。
- setName(): 設定執行緒名。
二、執行緒同步
如果多個執行緒共同對某個資料修改,則可能出現不可預料的結果,為了保證資料的正確性,需要對多個執行緒進行同步。 使用 Threading 物件的 Lock 和 Rlock 可以實現簡單的執行緒同步,這兩個物件都有 acquire 方法和 release 方法,對於那些需要每次只允許一個執行緒操作的資料,可以將其操作放到 acquire 和 release 方法之間。
利用執行緒同步,可以使部分程式碼只能同時被一個執行緒操作,當這部分程式碼被一個執行緒使用時,其他執行緒需要等待執行緒該執行緒處理完之後,才能輪到下一個執行緒呼叫
- 例項
利用多執行緒,每個執行緒獲取全域性變數num,然後對num進行1000000次的+1操作,如果沒有利用執行緒同步,程式碼如下:
import threading
num = 0 # 全域性變數
def sum(threadName,number):
global num
for i in range(number):
num += 1
print('{} num的值是: {}'.format(threadName,num))
class myThread(threading.Thread):
def __init__(self,number):
threading.Thread.__init__(self)
self.number = number
def run(self):
print('開始執行緒:%s' % (self.getName()))
sum(self.getName(),self.number)
print('結束執行緒:%s' % (self.getName()))
if __name__ == '__main__':
threads = [] # 建立執行緒列表
# 建立新執行緒
thread1 = myThread(number=1000000)
thread2 = myThread(number=1000000)
# 新增執行緒到執行緒列表
threads.append(thread1)
threads.append(thread2)
[t.start() for t in threads] # 開啟新執行緒
[t.join() for t in threads] # 等待所有執行緒完成
print('最後num的值是: {}'.format(num))
執行結果如下,可以看到兩個執行緒對num進行操作後,最後全域性變數num的值是1359993,和我們預想的結果(2000000)不一致。
開始執行緒:Thread-1
開始執行緒:Thread-2
Thread-1 num的值是: 1089741
結束執行緒:Thread-1
Thread-2 num的值是: 1359993
結束執行緒:Thread-2
最後num的值是: 1359993
下面我們利用執行緒同步,對上面程式碼進行改進,加入以下三行程式碼:
...
def run(self):
threadlock.acquire() # 獲取鎖,用於執行緒同步:當執行緒2進入時,如果以下程式碼有執行緒1在呼叫,則會暫停執行緒2,等待執行緒1解鎖後再到執行緒2進入
print('開始執行緒:%s' % (self.getName()))
sum(self.getName(),self.number)
threadlock.release() # 解鎖執行緒:當執行緒1解鎖後,執行緒2才能繼續執行
print('結束執行緒:%s' % (self.getName()))
if __name__ == '__main__':
threadlock = threading.Lock() # 建立執行緒鎖
...
執行結果如下:
開始執行緒:Thread-1
Thread-1 num的值是: 1000000
結束執行緒:Thread-1
開始執行緒:Thread-2
Thread-2 num的值是: 2000000
結束執行緒:Thread-2
最後num的值是: 2000000
可以看到,和我們預想的結果一致。
本作品採用《CC 協議》,轉載必須註明作者和本文連結