Python線程之如何解決共享變量問題
前面提到瞭銀行轉賬這個場景,展示瞭一個比較耗時的轉賬操作。
這篇繼續轉帳,下面展示一段程序,多個線程的操作都更改瞭amount
變量導致運行結果不對的問題。
前文說瞭轉賬問題
下面展示另一種轉賬的方式:
import random import threading import datetime import time xuewei = {'balance': 157} # amount為負數即是轉出金額 def transfer(money): name = threading.current_thread().getName() print("%s 給xuewei轉賬 %s " % (name, money)) xuewei['balance'] += money print("xuewei賬戶餘額:", xuewei['balance']) lists = [-7, 20, -20, 7] # 4次轉賬的數額,負數為學委的賬戶轉出,正數為他人轉入。 # 創建4個任務給學委轉賬上面lists的金額 threads = [] for i in range(4): amount = lists[i] name = "t-" + str(i) print("%s 計劃轉賬 %s" % (name, amount)) mythread = threading.Thread(name=name, target=lambda: transfer(amount)) threads.append(mythread) # 開始轉賬 for t in threads: t.start() # 等待3秒讓上面的轉賬任務都完成,我們在看看賬戶餘額 time.sleep(3) print("-" * 16) print("學委賬戶餘額:", xuewei['balance'])
這裡啟動瞭4個線程,每個線程內有個lambda
表達式,分別於學委的賬戶進行轉賬,但是最後結果是185. 而不是157.
下面是運行結果:
PS: 這隻是一種運行結果。多線程的運行結果不是永遠一樣的。
如何解決這個問題?
觀測結果我們發先amount
隻保留瞭最後一個值。
好,下面改造一下:
import random import threading import datetime import time xuewei = {'balance': 157} lists = [-7, 20, -20, 7] # 4次轉賬的數額,負數為學委的賬戶轉出,正數為他人轉入。 def transfer(amount): name = threading.current_thread().getName() print("%s 給xuewei轉賬 %s " % (name,amount)) xuewei['balance'] += amount print("xuewei賬戶餘額:", xuewei['balance']) # 創建4個任務給學委轉賬上面lists的金額 for i in range(4): amount = lists[i] name = str(i) # mythread = threading.Thread(name=name, target=lambda: transfer(amount)) def event(): print("%s 計劃轉賬 %s" % (name, amount)) transfer(amount) mythread = threading.Thread(name=name, target=event) mythread.start() # 等待3秒讓上面的轉賬任務都完成,我們在看看賬戶餘額 time.sleep(3) print("-" * 16) print("學委賬戶餘額:", xuewei['balance'])
學委這裡加瞭一個event
函數,把轉賬計劃打印出來。
從下面的一次運行結果看,event函數的輸出結果沒錯,所有”計劃轉賬“金額都如預期[-7, 20, -20 7]。 問題是transfer函數再多線程執行的時候,我們發現amount被多線程競爭修改瞭:
用戶0轉賬金額變成20
用戶1轉賬金額變成-20
用戶2轉賬金額變成7
用戶3轉賬金額變成7
也就是說,amount
被後面的線程修改瞭,但是前面線程還沒有執行完。
用戶0應該轉賬-7的,中間還沒有執行完畢,結果被線程1修改瞭amount為20,用戶0繼續執行轉賬,餘額變成177. 其他依次推理。
amount
這個變量被多個線程競爭修改瞭,這個就是程序的共享變量。
到底如何解決?
方法非常簡單:直接幹掉共享變量。
下面就是消除共享變量的方法: 讓共享變成每個線程訪問獨立運行空間
所以代碼改動如下:
import random import threading import datetime import time xuewei = {'balance': 157} lists = [-7, 20, -20, 7] # 4次轉賬的數額,負數為學委的賬戶轉出,正數為他人轉入。 # 我們不要依賴amount變量瞭 def transfer(): name = threading.current_thread().getName() xuewei['balance'] += lists[int(name)] #通過線程名字來獲取對應金額 print("xuewei賬戶餘額:", xuewei['balance']) # 創建4個任務給學委轉賬上面lists的金額 threads = [] for i in range(4): amount = lists[i] name = str(i) print("%s 計劃轉賬 %s" % (name, amount)) # mythread = threading.Thread(name=name, target=lambda: transfer()) def event(): transfer() mythread = threading.Thread(name=name, target=event) threads.append(mythread) # 開始轉賬 for t in threads: t.start() # 等待3秒讓上面的轉賬任務都完成,我們在看看賬戶餘額 time.sleep(3) print("-" * 16) print("學委賬戶餘額:", xuewei['balance'])
運行結果如下:
上面的代碼不管怎麼運行,運行多少次最後學委的賬戶都是157.
這次展示的另一種方式來避開多線程出現bug的方法,使用一個list下標跟線程名字一一對應,這樣隻要是對應名字的線程拿到的數值不錯錯亂。
到此這篇關於Python線程之如何解決共享變量問題的文章就介紹到這瞭,更多相關Python線程解決共享變量問題內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!