Preface:
- 要同時間執行兩個以上的函數,需用到多任務執行的模塊,例如
threading
模塊 - 線程(Thread)是實現多任務的一種手段
Introduction:
- python的thread模塊是比較底層的模塊,python的threading模塊是對thread做了一些包裝,可以更加方便的被使用
Notice:
Usage:
threading
模塊中有一個Thread
類Example I:
1
2
3
4
5
6
7
8
9
10
11
12
13import threading
import time
def sayHello():
print("Hello")
time.sleep(1)
if __name__ == '__main__':
for i in range(5):
#創建一個線程的物件
t = threading.Thread(target=sayHello)
#啟動線程
t.start()
- 主線程會等待子線程執行結束之後才會結束程序
查看線程信息(enumerate)
- 使用
threading
模塊下的enumerate
可獲取當前程序所有線程信息(包括主線程),返回一個列表1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import threading
from time import sleep
def sing():
print("I'm singing")
sleep(1)
def dance():
print("I'm dancing")
sleep(1)
if __name__ == '__main__':
print("In the Main")
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
while True:
length = len(threading.enumerate())
print("當前線程數為:%d"%length)
if length <= 1:
break
sleep(0.5) - 主線程會等到所有子線程都結束後才結束主線程
- 當調用
Thread
的時候,不會創建線程- 使用
Thread
創建出來的線程物件(線程實例化對象)調用start
方法的時候:- 才會創建線程
- 並讓線程開始運行
- 使用
result1
2
3
4
5
6In the Main
I'm singing
I'm dancing
當前線程數為:3
當前線程數為:3
當前線程數為:1
通過繼承Thread
類創建線程
1 | import threading |
- 上面使用
t = MyThread
創建一個線程物件,其與使用threading.Thread()
創建線程物件沒有差別 - 使用繼承的方法創建Thread,通常用於執行複雜操作時,也就是無法完全用
threading.Thread(target=函數名)
完整執行所有動作時使用 - 要執行的動作需寫在類的
run
方法中(必須定義)- 線程物件執行
start
方法時,會調用run
方法 run
方法中內容是甚麼,線程就執行什麼run
方法執行完後,線程即結束
- 線程物件執行
共享全局變量(重要)
- 多線程之間是共享全局變量的
共享全局變量遇到的問題
- 共享全局變量會遇到資源競爭的問題
- 兩個以上的線程對同一變量進行寫操作
線程同步(協同步調)
- 線程同步是解決資源競爭問題的方法
- 按預定的先後次序運行
- 可理解為線程A和B一塊配合,A執行到一定程度時要依靠B的某個結果,於是停下來,示意B運行,B執行
- 必須遵守原子性操作
- 牽涉到多線程的寫操作時,必須將以下三步全部執行完成,否則就不執行
- 獲取值
- 修改值
- 儲存值
- 牽涉到多線程的寫操作時,必須將以下三步全部執行完成,否則就不執行
互斥鎖
- 當多個線程幾乎同時修改某一個共享數據時,需要進行同步控制
- 最簡單的同步機制:引入互斥鎖
- 互斥鎖為資源引入一個狀態:鎖定/非鎖定
- 在執行時只允許一個線程進入獲取資源,別的線程無法進入
threading
模塊中定義了Lock
類- 上鎖最好上越少代碼越好
- 需注意死鎖狀況發生
- 避免死鎖:
- 程序盡量避免使用計時的方式(銀行家演算法)
- 添加超時(timeout)時間等
- 避免死鎖:
1 | #創建鎖物件 |
- 如果鎖物件之前是未上鎖的,那麼調用
acquire
方法便不會堵塞 - 如果在調用
acquire
對鎖物件上鎖之前,已經被其他線程先行上鎖,會堵塞到鎖物件被release
為止
未上鎖
1 | import threading |
result
1
in the main Thread, number= 1660809
- 3.
1
in the main Thread, number= 1594271
1
in the main Thread, number= 1704507
有上鎖
1 | import threading |
result1
in the main Thread, number= 2000000
傳遞參數
- 使用線程執行函數時傳遞參數(args)
- 指定將來創建線程物件時,傳遞什麼參數過去
threading.Thread(taget=函數名,args=(參數))
- 請注意args參數接受必須為一元組(重要)
1 | import threading |
result1
2
3-----in test1 [11, 22, 33]
----- in test2 Thread
int the main Thread