淺談python多執行緒和多執行緒變數共享問題介紹
阿新 • • 發佈:2020-04-18
1、demo
第一個程式碼是多執行緒的簡單使用,編寫了執行緒如何執行函式和類。
import threading import time class ClassName(threading.Thread): """建立類,通過多執行緒執行""" def run(self): for i in range(5): print(i) time.sleep(1) def sing(): for i in range(1,11): print("唱歌第 %d 遍" % i) time.sleep(1) def dance(): for i in range(1,16): print("跳舞第 %d 遍" % i) time.sleep(1) def main(): t1 = threading.Thread(target = sing) t2 = threading.Thread(target = dance) t = ClassName() # 啟動執行緒 t1.start() t2.start() t.start() while True: length = len(threading.enumerate()) print("正在執行的執行緒有 %s" %threading.enumerate()) if length <= 1: break time.sleep(1) if __name__ == '__main__': main()
執行結果可以看到函式 sing、dance和類在同時執行,執行效果太長就不方截圖了
2、多執行緒共享變數
通過定義全域性變數,然後再test1函式類部進行更改全域性變數,test2列印全域性變數。
import threading import time #定義全域性變數 g_num = 0 def test1(): """函式test1對全域性變數進行更改""" global g_num for i in range(1,10): g_num += 1 print("--- test1 執行緒 g_num = %d--- " % g_num) def test2(): """函式test2 列印全域性變數""" print("--- test2 執行緒 g_num = %d--- " % g_num) def main(): t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) # 啟動執行緒 t1.start() # 增加睡眠是為了保證優先執行函式test1 time.sleep(1) t2.start() print("--- 主執行緒 g_num = %d--- " % g_num) if __name__ == '__main__': main()
執行結果可以看出,在主執行緒和建立的兩個執行緒中讀取的是一樣的值,既可以表明在多執行緒中變數共享
3、資源競爭
在多執行緒兩個函式中同時更改一個變數時,由於cpu的計算能力,當修改引數的程式碼塊無法一次性執行完成時,就會產生資源競爭
import threading import time # 定義全域性變數 g_num = 0 def test1(num): """函式test1對全域性變數進行更改""" global g_num for i in range(num): g_num += 1 print("test1 執行緒 g_num = %d---" % g_num) def test2(num): """函式test2對全域性變數進行更改""" global g_num for i in range(num): g_num += 1 print("tes2 執行緒 g_num = %d---" % g_num) def main(): t1 = threading.Thread(target=test1,args=(1000000,)) t2 = threading.Thread(target=test2,)) t1.start() t2.start() time.sleep(1) print("主執行緒 g_num = %d---" % g_num) if __name__ == '__main__': main()
可以先試試傳遞引數為100時,可以看到g_num = 200 這是因為函式程式碼可以一次性執行完成,當引數為1000000時程式碼無法一次性執行完成,g_num!= 2000000
4、互斥鎖
互斥鎖可以解決資源競爭的問題,原理很簡單,通過對程式碼塊上鎖,保證該程式碼執行完成前,其它程式碼無法進行修改。執行完成後解鎖,其它程式碼就可以執行了。
import threading import time # 建立變數 g_num = 0 # 建立鎖預設為開鎖狀態 mutex = threading.Lock() def test1(num): global g_num for i in range(num): # 上鎖 mutex.acquire() g_num += 1 # 解鎖 mutex.release() print("--- test1 執行緒 g_num = %d---" % g_num) def test2(num): global g_num for i in range(num): # 上鎖 mutex.acquire() g_num += 1 # 解鎖 mutex.release() print("--- test2 執行緒 g_num = %d---" % g_num) def main(): t1 = threading.Thread(target=test1,)) t1.start() t2.start() time.sleep(1) print("--- 主執行緒 g_num = %d---" % g_num) if __name__ == '__main__': main()
可以看到加了鎖之後,程式碼執行不會出現資源競爭,結果也是正常的。互斥鎖,上鎖的程式碼越少越好。
5、死鎖
當出現多個鎖時,就可能會產生死鎖這個情況。當關閉一個鎖時,這個鎖已經為關閉狀態的話,程式就會阻塞。就如同下面這個程式碼中。函式test1關閉mutexB鎖時,函式test2提前將其關閉了,未進行解鎖,程式就會一直阻塞。
import threading import time # 建立兩個鎖A,B mutexA = threading.Lock() mutexB = threading.Lock() def test1(): # 對muctexA上鎖 mutexA.acquire() # mutexA上鎖後,延時1秒,等待mutexB上鎖 print("test1 ---do1---up---") time.sleep(1) # 此時會堵塞,因為mutexB已經上鎖 mutexB.acquire() print("test1 ---do1---down---") mutexB.release() # 對mutexA解鎖 mutexA.release() def test2(): # 對muctexB上鎖 mutexB.acquire() # mutexB上鎖後,延時1秒,等待mutexA上鎖 print("test2 ---do1---up---") time.sleep(1) # 此時會堵塞,因為mutexB已經上鎖 mutexA.acquire() print("test2 ---do1---down---") mutexA.release() # 對mutexA解鎖 mutexB.release() def main(): t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) t1.start() t2.start() if __name__ == '__main__': main()
程式碼執行效果可以看到程式會一直阻塞
解決方法
1、在程式編寫時,就需要注意避免死鎖
2、可以參考銀行家演算法
到此這篇關於淺談python多執行緒和多執行緒變數共享問題介紹的文章就介紹到這了,更多相關python 多執行緒變數共享內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!