淺談python多線程和多線程變量共享問題介紹
1、demo
第一個(gè)代碼是多線程的簡(jiǎn)單使用,編寫了線程如何執(zhí)行函數(shù)和類。
import threading
import time
class ClassName(threading.Thread):
"""創(chuàng)建類,通過多線程執(zhí)行"""
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()
# 啟動(dòng)線程
t1.start()
t2.start()
t.start()
while True:
length = len(threading.enumerate())
print("正在運(yùn)行的線程有 %s" %threading.enumerate())
if length <= 1:
break
time.sleep(1)
if __name__ == '__main__':
main()
執(zhí)行結(jié)果可以看到函數(shù) sing、dance和類在同時(shí)執(zhí)行,執(zhí)行效果太長(zhǎng)就不方截圖了
2、多線程共享變量
通過定義全局變量,然后再test1函數(shù)類部進(jìn)行更改全局變量,test2打印全局變量。
import threading
import time
#定義全局變量
g_num = 0
def test1():
"""函數(shù)test1對(duì)全局變量進(jìn)行更改"""
global g_num
for i in range(1,10):
g_num += 1
print("--- test1 線程 g_num = %d--- " % g_num)
def test2():
"""函數(shù)test2 打印全局變量"""
print("--- test2 線程 g_num = %d--- " % g_num)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
# 啟動(dòng)線程
t1.start()
# 增加睡眠是為了保證優(yōu)先執(zhí)行函數(shù)test1
time.sleep(1)
t2.start()
print("--- 主線程 g_num = %d--- " % g_num)
if __name__ == '__main__':
main()
執(zhí)行結(jié)果可以看出,在主線程和創(chuàng)建的兩個(gè)線程中讀取的是一樣的值,既可以表明在多線程中變量共享

3、資源競(jìng)爭(zhēng)
在多線程兩個(gè)函數(shù)中同時(shí)更改一個(gè)變量時(shí),由于cpu的計(jì)算能力,當(dāng)修改參數(shù)的代碼塊無法一次性執(zhí)行完成時(shí),就會(huì)產(chǎn)生資源競(jìng)爭(zhēng)
import threading
import time
# 定義全局變量
g_num = 0
def test1(num):
"""函數(shù)test1對(duì)全局變量進(jìn)行更改"""
global g_num
for i in range(num):
g_num += 1
print("test1 線程 g_num = %d---" % g_num)
def test2(num):
"""函數(shù)test2對(duì)全局變量進(jìn)行更改"""
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, args=(1000000, ))
t1.start()
t2.start()
time.sleep(1)
print("主線程 g_num = %d---" % g_num)
if __name__ == '__main__':
main()
可以先試試傳遞參數(shù)為100時(shí),可以看到g_num = 200 這是因?yàn)楹瘮?shù)代碼可以一次性執(zhí)行完成,當(dāng)參數(shù)為1000000時(shí)代碼無法一次性執(zhí)行完成,g_num!= 2000000

4、互斥鎖
互斥鎖可以解決資源競(jìng)爭(zhēng)的問題,原理很簡(jiǎn)單,通過對(duì)代碼塊上鎖,保證該代碼執(zhí)行完成前,其它代碼無法進(jìn)行修改。執(zhí)行完成后解鎖,其它代碼就可以執(zhí)行了。
import threading
import time
# 創(chuàng)建變量
g_num = 0
# 創(chuàng)建鎖默認(rèn)為開鎖狀態(tài)
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, args=(1000000, ))
t2 = threading.Thread(target=test2, args=(1000000, ))
t1.start()
t2.start()
time.sleep(1)
print("--- 主線程 g_num = %d---" % g_num)
if __name__ == '__main__':
main()
可以看到加了鎖之后,代碼執(zhí)行不會(huì)出現(xiàn)資源競(jìng)爭(zhēng),結(jié)果也是正常的。互斥鎖,上鎖的代碼越少越好。

5、死鎖
當(dāng)出現(xiàn)多個(gè)鎖時(shí),就可能會(huì)產(chǎn)生死鎖這個(gè)情況。當(dāng)關(guān)閉一個(gè)鎖時(shí),這個(gè)鎖已經(jīng)為關(guān)閉狀態(tài)的話,程序就會(huì)阻塞。就如同下面這個(gè)代碼中。函數(shù)test1關(guān)閉mutexB鎖時(shí),函數(shù)test2提前將其關(guān)閉了,未進(jìn)行解鎖,程序就會(huì)一直阻塞。
import threading
import time
# 創(chuàng)建兩個(gè)鎖A, B
mutexA = threading.Lock()
mutexB = threading.Lock()
def test1():
# 對(duì)muctexA上鎖
mutexA.acquire()
# mutexA上鎖后,延時(shí)1秒,等待mutexB上鎖
print("test1 ---do1---up---")
time.sleep(1)
# 此時(shí)會(huì)堵塞,因?yàn)閙utexB已經(jīng)上鎖
mutexB.acquire()
print("test1 ---do1---down---")
mutexB.release()
# 對(duì)mutexA解鎖
mutexA.release()
def test2():
# 對(duì)muctexB上鎖
mutexB.acquire()
# mutexB上鎖后,延時(shí)1秒,等待mutexA上鎖
print("test2 ---do1---up---")
time.sleep(1)
# 此時(shí)會(huì)堵塞,因?yàn)閙utexB已經(jīng)上鎖
mutexA.acquire()
print("test2 ---do1---down---")
mutexA.release()
# 對(duì)mutexA解鎖
mutexB.release()
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
代碼執(zhí)行效果可以看到程序會(huì)一直阻塞
解決方法
1、在程序編寫時(shí),就需要注意避免死鎖
2、可以參考銀行家算法

到此這篇關(guān)于淺談python多線程和多線程變量共享問題介紹的文章就介紹到這了,更多相關(guān)python 多線程變量共享內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python爬蟲之自動(dòng)爬取某車之家各車銷售數(shù)據(jù)
應(yīng)朋友要求,幫忙采集某車之家的一些汽車品牌的銷售數(shù)據(jù),包含購車時(shí)間、車型、經(jīng)銷商、裸車價(jià)等一類信息. 今天我們就簡(jiǎn)單演示一下采集過程,大家可以根據(jù)自己的興趣進(jìn)行拓展.比如采集自己喜歡的品牌汽車數(shù)據(jù)進(jìn)行統(tǒng)計(jì)分析等等,需要的朋友可以參考下2021-06-06
PyTorch并行訓(xùn)練DistributedDataParallel完整demo
這篇文章主要為大家介紹了PyTorch并行訓(xùn)練DistributedDataParallel完整demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
使用Python實(shí)現(xiàn)操作控制鼠標(biāo)和鍵盤
Python 有很多的庫可以實(shí)現(xiàn)各種各樣的功能,比如使用 pynput 操作,下面小編就來和大家詳細(xì)介紹一下如何使用pynput進(jìn)行操作控制鼠標(biāo)和鍵盤吧2024-02-02
python通過zlib實(shí)現(xiàn)壓縮與解壓字符串的方法
這篇文章主要介紹了python通過zlib實(shí)現(xiàn)壓縮與解壓字符串的方法,較為詳細(xì)的介紹了zlib的用法及使用zlib.compressobj和zlib.decompressobj對(duì)文件進(jìn)行壓縮解壓的方法,需要的朋友可以參考下2014-11-11

