python進階之多線程對同一個全局變量的處理方法
通常情況下:
from threading import Thread global_num = 0 def func1(): global global_num for i in range(1000000): global_num += 1 print('---------func1:global_num=%s--------'%global_num) def func2(): global global_num for i in range(1000000): global_num += 1 print('--------fun2:global_num=%s'%global_num) print('global_num=%s'%global_num) lock = Lock() t1 = Thread(target=func1) t1.start() t2 = Thread(target=func2) t2.start()
輸出結(jié)果:
global_num=0 ---------func1:global_num=1492752-------- --------fun2:global_num=1515462
#由于多線程不像多進程一樣,每一個進程都一個獨立的資源塊,線程之間是共享主線程的一個資源塊(雖然這樣說不合適)
#這樣雖然方便了線程之間的數(shù)據(jù)傳遞,但是又會由于線程之間執(zhí)行順序的不確定,導(dǎo)致最后的結(jié)果不是應(yīng)該輸出的正確結(jié)果。
#例如下面的例程,如果沒有添加global_flag標(biāo)志全局變量,就會出現(xiàn),雖然邏輯上最后的結(jié)果是2000000(之所以選擇這么大的一個數(shù),是因為可以更明顯的看出#這個問題),
#但是實際上并不是這個結(jié)果,而是一個小于2000000的結(jié)果,但是不排出偶然會出現(xiàn)2000000,這是一個極為理想的結(jié)果,這是為什么呢?
#主要還是由于線程被cpu調(diào)用的順序不確定。具體來講就是當(dāng)主線程創(chuàng)建出兩個子線程,分別是t1和t2,他們有分別指向func1()和func2()。
#在這兩個線程中的函數(shù)中,都有一句“global_num += 1”,在計算機內(nèi)部cpu執(zhí)行時,這一條語句實際上是兩個過程:第一個過程是從內(nèi)存中讀取global_num的值,完成加一操作,這個時候global_num的值還是原來的值;第二個過程是將求和的值付給global_num,這時候global_num的值才會更新。在程序執(zhí)行過程中會出現(xiàn)這種
#情況:當(dāng)cpu在執(zhí)行線程t1中的語句到求和那條語句時,在執(zhí)行完第一個過程停了下來,將線程t1拋出,轉(zhuǎn)而執(zhí)行線程t2,當(dāng)線程執(zhí)行一段時間后也出現(xiàn)這中情況
#有轉(zhuǎn)而執(zhí)行線程t1,這時,正好執(zhí)行求和語句的第二個過程,完成最初的賦值,那么這一段時間內(nèi)的整個求和就等于沒做,所以出現(xiàn)這中最后結(jié)果不是2000000的##情況
#解決這種情況可以利用添加一個變量,利用“輪詢”的方式執(zhí)行,但是這樣做的效率很低,而且還浪費cpu,所以一般采用“通知”方式來做。
輪詢方式:
from threading import Thread global_num = 0 global_flag = 0 def func1(): global global_num global global_flag if global_flag == 0: for i in range(1000000): global_num += 1 global_flag = 1 print('---------func1:global_num=%s--------'%global_num) def func2(): global global_num while True: if global_flag != 0: for i in range(1000000): global_num += 1 break print('--------fun2:global_num=%s'%global_num) print('global_num=%s'%global_num) t1 = Thread(target=func1) t1.start() t2 = Thread(target=func2) t2.start()
運行結(jié)果:
global_num=0 ---------func1:global_num=1000000-------- --------fun2:global_num=2000000
通知方式:
from threading import Thread,Lock global_num = 0 def func1(): global global_num for i in range(1000000): lock.acquire()#兩個線程會最開始搶這個鎖,拿到鎖就會處于關(guān)鎖,執(zhí)行后面的程序,其他線程執(zhí)行處于監(jiān)聽狀態(tài),等待這個線程開鎖,再搶鎖 global_num += 1 lock.release() print('---------func1:global_num=%s--------'%global_num) def func2(): global global_num for i in range(1000000): lock.acquire() global_num += 1 lock.release() print('--------fun2:global_num=%s'%global_num) print('global_num=%s'%global_num) lock = Lock() t1 = Thread(target=func1) t1.start() t2 = Thread(target=func2) t2.start()
輸出結(jié)果:
global_num=0 ---------func1:global_num=1901175-------- --------fun2:global_num=2000000
以上這篇python進階之多線程對同一個全局變量的處理方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Pandas?DataFrame列快速轉(zhuǎn)換為列表(3秒學(xué)會!)
這篇文章主要給大家介紹了關(guān)于Pandas?DataFrame列如何快速轉(zhuǎn)換為列表的相關(guān)資料,在Python的pandas庫中可以使用DataFrame的tolist()方法將DataFrame轉(zhuǎn)化為列表,需要的朋友可以參考下2023-10-10python 安裝教程之Pycharm安裝及配置字體主題,換行,自動更新
這篇文章主要介紹了python 安裝教程之Pycharm安裝及配置字體主題,換行,自動更新,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03pytorch之pytorch?hook和關(guān)于pytorch?backward過程問題
這篇文章主要介紹了pytorch之pytorch?hook和關(guān)于pytorch?backward過程問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09Pytorch-Geometric中的Message?Passing使用及說明
這篇文章主要介紹了Pytorch-Geometric中的Message?Passing使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12python 高效去重復(fù) 支持GB級別大文件的示例代碼
今天小編就為大家分享一篇python 高效去重復(fù) 支持GB級別大文件的示例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11python游戲開發(fā)之視頻轉(zhuǎn)彩色字符動畫
這篇文章主要為大家詳細介紹了python游戲開發(fā)之視頻轉(zhuǎn)彩色字符動畫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04