<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
執行緒安全,名字就非常直接,在多執行緒情況下是安全的,多執行緒操作上的安全。
比如一個計算加法的函數,不管是一千個還是一萬個執行緒,我們希望它執行的結果總是正確的,1+1 必須永遠等於2, 而不是執行緒少的時候1+1 變成3或者4了。
通常我們都用執行緒安全來修飾一個類,修飾一個函數:
我們會說我設計的這個類是執行緒安全的
這意味著,在多執行緒環境下,同時呼叫這個類的函數不會出現函數設定預期之外的異常(上述的1+1=3的情況)
dict 和 list,tuple這些都是執行緒安全。
它們是被全域性直譯器保障了,這個鎖:GIL(全域性直譯器鎖)確保了任何時候只能有一個執行緒執行相應操作的位元組碼。參考
但是這番話也是說的不清不楚的。
現在我們拿轉賬來解析吧:
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是安全的。
但是我們把賦值修改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的數值一樣):
我們看到dict還是扛不住多個執行緒反覆的寫操作。
這裡區別是:每個執行緒只對xuewei_account進行大量讀寫,雖然dict是安全的,但是多個執行緒中間穿插修改了account,程式方法棧出現操作到舊值(看下面的圖)。
主要是下面這段程式碼:
xuewei_account[‘amount'] += money # 即是 xuewei_account[‘amount'] = xuewei_account[‘amount']+ money
再一步抽象簡化可以寫成:
a = a + b
每個執行緒都執行 +b 操作,最後a的值應該是a+2b。
上面的操作意味這下面的情況發生了:
在某個執行緒中可能出現某一個執行緒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
比如下面的加法函數,不管多少個執行緒呼叫,返回值永遠是預期的a+b。
def add(a, b): return a + b
許我們可以把多執行緒轉換為單執行緒,這個需要一個執行緒安全的媒介。
到此這篇關於Python執行緒之認識執行緒安全 的文章就介紹到這了,更多相關認識Python執行緒安全 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45