通常情況下:
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()
輸出結果:
global_num=0---------func1:global_num=1492752----------------fun2:global_num=1515462
#由于多線程不像多進程一樣,每一個進程都一個獨立的資源塊,線程之間是共享主線程的一個資源塊(雖然這樣說不合適)
#這樣雖然方便了線程之間的數據傳遞,但是又會由于線程之間執行順序的不確定,導致最后的結果不是應該輸出的正確結果。
#例如下面的例程,如果沒有添加global_flag標志全局變量,就會出現,雖然邏輯上最后的結果是2000000(之所以選擇這么大的一個數,是因為可以更明顯的看出#這個問題),
#但是實際上并不是這個結果,而是一個小于2000000的結果,但是不排出偶然會出現2000000,這是一個極為理想的結果,這是為什么呢?
#主要還是由于線程被cpu調用的順序不確定。具體來講就是當主線程創建出兩個子線程,分別是t1和t2,他們有分別指向func1()和func2()。
#在這兩個線程中的函數中,都有一句“global_num += 1”,在計算機內部cpu執行時,這一條語句實際上是兩個過程:第一個過程是從內存中讀取global_num的值,完成加一操作,這個時候global_num的值還是原來的值;第二個過程是將求和的值付給global_num,這時候global_num的值才會更新。在程序執行過程中會出現這種
#情況:當cpu在執行線程t1中的語句到求和那條語句時,在執行完第一個過程停了下來,將線程t1拋出,轉而執行線程t2,當線程執行一段時間后也出現這中情況
#有轉而執行線程t1,這時,正好執行求和語句的第二個過程,完成最初的賦值,那么這一段時間內的整個求和就等于沒做,所以出現這中最后結果不是2000000的##情況
#解決這種情況可以利用添加一個變量,利用“輪詢”的方式執行,但是這樣做的效率很低,而且還浪費cpu,所以一般采用“通知”方式來做。
輪詢方式:
from threading import Thread global_num = 0global_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()
新聞熱點
疑難解答