溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python線程怎么解決共享變量問題

發(fā)布時間:2022-02-24 13:36:44 來源:億速云 閱讀:251 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Python線程怎么解決共享變量問題”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強(qiáng),希望這篇“Python線程怎么解決共享變量問題”文章能幫助大家解決問題。

下面展示另一種轉(zhuǎn)賬的方式:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}


# amount為負(fù)數(shù)即是轉(zhuǎn)出金額
def transfer(money):
    name = threading.current_thread().getName()
    print("%s 給xuewei轉(zhuǎn)賬 %s " % (name, money))
    xuewei['balance'] += money
    print("xuewei賬戶余額:", xuewei['balance'])


lists = [-7, 20, -20, 7]  # 4次轉(zhuǎn)賬的數(shù)額,負(fù)數(shù)為學(xué)委的賬戶轉(zhuǎn)出,正數(shù)為他人轉(zhuǎn)入。
# 創(chuàng)建4個任務(wù)給學(xué)委轉(zhuǎn)賬上面lists的金額
threads = []
for i in range(4):
    amount = lists[i]
    name = "t-" + str(i)
    print("%s 計劃轉(zhuǎn)賬 %s" % (name, amount))
    mythread = threading.Thread(name=name, target=lambda: transfer(amount))
    threads.append(mythread)

# 開始轉(zhuǎn)賬
for t in threads:
    t.start()

# 等待3秒讓上面的轉(zhuǎn)賬任務(wù)都完成,我們在看看賬戶余額
time.sleep(3)
print("-" * 16)
print("學(xué)委賬戶余額:", xuewei['balance'])

這里啟動了4個線程,每個線程內(nèi)有個lambda表達(dá)式,分別于學(xué)委的賬戶進(jìn)行轉(zhuǎn)賬,但是最后結(jié)果是185. 而不是157.

下面是運行結(jié)果:

Python線程怎么解決共享變量問題

PS: 這只是一種運行結(jié)果。多線程的運行結(jié)果不是永遠(yuǎn)一樣的。

如何解決這個問題?

觀測結(jié)果我們發(fā)先amount只保留了最后一個值。

好,下面改造一下:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}

lists = [-7, 20, -20, 7]  # 4次轉(zhuǎn)賬的數(shù)額,負(fù)數(shù)為學(xué)委的賬戶轉(zhuǎn)出,正數(shù)為他人轉(zhuǎn)入。


def transfer(amount):
    name = threading.current_thread().getName()
    print("%s 給xuewei轉(zhuǎn)賬 %s " % (name,amount))
    xuewei['balance'] += amount
    print("xuewei賬戶余額:", xuewei['balance'])


# 創(chuàng)建4個任務(wù)給學(xué)委轉(zhuǎn)賬上面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 計劃轉(zhuǎn)賬 %s" % (name, amount))
        transfer(amount)
    mythread = threading.Thread(name=name, target=event)
    mythread.start()


# 等待3秒讓上面的轉(zhuǎn)賬任務(wù)都完成,我們在看看賬戶余額
time.sleep(3)
print("-" * 16)
print("學(xué)委賬戶余額:", xuewei['balance'])

學(xué)委這里加了一個event函數(shù),把轉(zhuǎn)賬計劃打印出來。

從下面的一次運行結(jié)果看,event函數(shù)的輸出結(jié)果沒錯,所有”計劃轉(zhuǎn)賬“金額都如預(yù)期[-7, 20, -20 7]。 問題是transfer函數(shù)再多線程執(zhí)行的時候,我們發(fā)現(xiàn)amount被多線程競爭修改了:

用戶0轉(zhuǎn)賬金額變成20
用戶1轉(zhuǎn)賬金額變成-20
用戶2轉(zhuǎn)賬金額變成7
用戶3轉(zhuǎn)賬金額變成7

Python線程怎么解決共享變量問題

也就是說,amount被后面的線程修改了,但是前面線程還沒有執(zhí)行完。
用戶0應(yīng)該轉(zhuǎn)賬-7的,中間還沒有執(zhí)行完畢,結(jié)果被線程1修改了amount為20,用戶0繼續(xù)執(zhí)行轉(zhuǎn)賬,余額變成177. 其他依次推理。

amount這個變量被多個線程競爭修改了,這個就是程序的共享變量。

到底如何解決?

方法非常簡單:直接干掉共享變量。

下面就是消除共享變量的方法: 讓共享變成每個線程訪問獨立運行空間

所以代碼改動如下:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}

lists = [-7, 20, -20, 7]  # 4次轉(zhuǎn)賬的數(shù)額,負(fù)數(shù)為學(xué)委的賬戶轉(zhuǎn)出,正數(shù)為他人轉(zhuǎn)入。
# 我們不要依賴amount變量了
def transfer():
    name = threading.current_thread().getName()
    xuewei['balance'] += lists[int(name)] #通過線程名字來獲取對應(yīng)金額
    print("xuewei賬戶余額:", xuewei['balance'])

# 創(chuàng)建4個任務(wù)給學(xué)委轉(zhuǎn)賬上面lists的金額
threads = []
for i in range(4):
    amount = lists[i]
    name = str(i)
    print("%s 計劃轉(zhuǎn)賬 %s" % (name, amount))
    # mythread = threading.Thread(name=name, target=lambda: transfer())
    def event():
        transfer()
    mythread = threading.Thread(name=name, target=event)
    threads.append(mythread)

# 開始轉(zhuǎn)賬
for t in threads:
    t.start()

# 等待3秒讓上面的轉(zhuǎn)賬任務(wù)都完成,我們在看看賬戶余額
time.sleep(3)
print("-" * 16)
print("學(xué)委賬戶余額:", xuewei['balance'])

運行結(jié)果如下:

Python線程怎么解決共享變量問題

上面的代碼不管怎么運行,運行多少次最后學(xué)委的賬戶都是157.

這次展示的另一種方式來避開多線程出現(xiàn)bug的方法,使用一個list下標(biāo)跟線程名字一一對應(yīng),這樣只要是對應(yīng)名字的線程拿到的數(shù)值不錯錯亂。

關(guān)于“Python線程怎么解決共享變量問題”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI