首頁 > 軟體

Python執行緒之如何解決共用變數問題

2022-02-24 13:00:59

前面提到了銀行轉賬這個場景,展示了一個比較耗時的轉賬操作。

這篇繼續轉帳,下面展示一段程式,多個執行緒的操作都更改了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執行緒解決共用變數問題內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com