91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

Python線程安全實例分析

發布時間:2022-02-24 13:39:18 來源:億速云 閱讀:183 作者:iii 欄目:開發技術

這篇文章主要介紹“Python線程安全實例分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Python線程安全實例分析”文章能幫助大家解決問題。

一、什么是線程安全?

線程安全,名字就非常直接,在多線程情況下是安全的,多線程操作上的安全。

比如一個計算加法的函數,不管是一千個還是一萬個線程,我們希望它執行的結果總是正確的,1+1 必須永遠等于2, 而不是線程少的時候1+1 變成3或者4了。

通常我們都用線程安全來修飾一個類,修飾一個函數:

我們會說我設計的這個類是線程安全的
這意味著,在多線程環境下,同時調用這個類的函數不會出現函數設置預期之外的異常(上述的1+1=3的情況)

二、在Python中有哪些類是線程安全的?

dict 和 list,tuple這些都是線程安全。

它們是被全局解釋器保障了,這個鎖:GIL(全局解釋器鎖)確保了任何時候只能有一個線程執行相應操作的字節碼。參考

Python線程安全實例分析

但是這番話也是說的不清不楚的。

現在我們拿轉賬來解析吧:

xuewei_account = dict()
xuewei_account['amount'] = 100

# amount為負數即是轉出金額
def transfer(money):
    xuewei_account['amount'] +=  money

如上,代碼為一個函數對jb_account(賬戶)進行轉入金額操作。

這里用了dict類型,GIL會保證只有一個線程操作賬戶。

下面是多個線程進行操作的代碼:

import random
import threading
import datetime
import time

xuewei_account = dict()
xuewei_account['amount'] = 100


# amount為負數即是轉出金額
def transfer(money):
    xuewei_account['amount'] +=  money


# 創建4個任務給重復學委賬戶轉賬
threads = []
for i in range(200):
    t1 = threading.Thread(target=lambda: transfer(-1))
    threads.append(t1)
    t2 = threading.Thread(target=lambda: transfer(1))
    threads.append(t2)

for t in threads:
    t.start()
    
# 這次不用sleep了,用join來等待所有線程執行完畢
# join函數必須線程start后才能調用,否則出錯。
for t in threads:
    t.join()

print("-" * 16)
print("活躍線程數:", threading.active_count())
print("活躍線程:", threading.current_thread().name)
print("學委賬戶余額:", xuewei_account)

這段代碼運行的輸出結果正常,因為是反復+1/-1,最后肯定是恢復原賬戶余額。

雖然多個線程,但是每個線程只對xuewei_account進行一次讀寫,這時候dict是安全的。

Python線程安全實例分析

但是我們把賦值修改dict的操作變多之后(特別是一個線程內反復多次獲取值然后修改),像下面的代碼:

import random
import threading
import datetime
import time

xuewei_account = dict()
xuewei_account['amount'] = 100


# amount為負數即是轉出金額
def transfer(money):
    for i in range(100000):
        xuewei_account['amount'] = xuewei_account['amount'] + money


# 創建400個任務重復給學委賬戶轉賬
threads = []
for i in range(200):
    t1 = threading.Thread(target=lambda: transfer(-1))
    threads.append(t1)
    t2 = threading.Thread(target=lambda: transfer(1))
    threads.append(t2)

for t in threads:
    t.start()
for t in threads:
    t.join()

print("-" * 16)
print("活躍線程數:", threading.active_count())
print("活躍線程:", threading.current_thread().name)
print("學委賬戶余額:", xuewei_account)

這是某一次運行結果(不保證每次acount的數值一樣):

Python線程安全實例分析

我們看到dict還是扛不住多個線程反復的寫操作。

這里區別是:每個線程只對xuewei_account進行大量讀寫,雖然dict是安全的,但是多個線程中間穿插修改了account,程序方法棧出現操作到舊值(看下面的圖)。

主要是下面這段代碼:

xuewei_account[‘amount'] += money 
# 即是 xuewei_account[‘amount'] = xuewei_account[‘amount']+ money

再一步抽象簡化可以寫成:

a = a + b

每個線程都執行 +b 操作,最后a的值應該是a+2b。

上面的操作意味這下面的情況發生了:

Python線程安全實例分析

在某個線程中可能出現某一個線程T1獲取了a值 ,準備加上b。

另外一個線程T2已經完成了a+b操作,把a的值變成了a+b了。

但是接下來T1 拿了a的值再執行a+b操作,把a的值變成a+b。

這樣就少加了一個b,本來最后結果是a+2b 的變成了 a+b(因為T1拿了a的舊值,中間T2執行完,T1才繼續執行)

當然實際多線程之間交互比上圖還要隨機。

三、如何做到真正線程安全?

dict讀取數據是線程安全,但是被反復讀寫就容易出現數據混亂。

如果我們要設計一個線程安全的函數,那么它必須不涉及任何共享變量或者是完全沒有狀態依賴的函數

def thread_safe_method():
    pass

1.無狀態函數

比如下面的加法函數,不管多少個線程調用,返回值永遠是預期的a+b。

def add(a, b):
    return a + b

2.另一種 化繁為簡

許我們可以把多線程轉換為單線程,這個需要一個線程安全的媒介。

關于“Python線程安全實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武安市| 丽江市| 长寿区| 赤壁市| 吴江市| 包头市| 遂溪县| 渭源县| 孝义市| 德庆县| 通州区| 咸丰县| 扎囊县| 陕西省| 翁牛特旗| 武冈市| 灵川县| 宜君县| 习水县| 台中市| 洛浦县| 阿克| 元朗区| 新和县| 岳阳县| 无棣县| 灌南县| 三河市| 灌阳县| 上高县| 丰台区| 西宁市| 临沭县| 积石山| 洱源县| 平舆县| 都安| 永修县| 雷山县| 湘西| 新巴尔虎右旗|