您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Python多線程下list的案例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
list 是 Python 常用的幾個基本數據類型之一.正常情況下我們會對 list 有增刪改查的操作,顯然易見不會有任何問題.那么如果我們試著在多線程下操作list 會有問題嗎?
多線程下的 list
安全 or 不安全? 不安全!
通常我們說的線程安全是指針對某個數據結構的所有操作都是線程安全,在這種定義下,Python 常用的數據結構 list,dict,str
等都是線程不安全的
盡管多線程下的 list
是線程不安全的,但是在 append
的操作下是它又是線程安全的.
如何判斷線程安全呢?
對于線程安全不安全,我們可以通過極端條件下去復現,從而得出結論。比如說判斷 list
是否線程安全
import threading import time # 隨意設置 count 的值,值越大錯誤拋出的越快 count = 1000 l = [] def add(): for i in range(count): l.append(i) time.sleep(0.0001) def remove(): for i in range(count): l.remove(i) time.sleep(0.0001) t1 = threading.Thread(target=add) t2 = threading.Thread(target=remove) t1.start() t2.start() t1.join() t2.join() print(l)
有時候一次運行并不一定就會出錯,多次重試之后會出現類似下面的錯誤
很顯然這種操作方式不具有普適性,如果要是歐氣太強,說不定會一直不出現異常。
那么出了這種方式,有沒有比較簡單有效的方法嗎?答案是有的
dis
dis 庫是 Python 自帶的一個庫,可以用來分析字節碼。這里我們需要有這樣的認識,字節碼的每一行都是一個原子操作,多線程切換就是以原子操作為單位的,如果一個操作需要兩行字節碼就說明它是線程不安全的
remove
這里我們先看一下上面 list
的 remove
操作
>>> import dis >>> def test_remove(): ... a = [1] ... a.remove(0) ... >>> dis.dis(test_remove) 2 0 LOAD_CONST 1 (1) 2 BUILD_LIST 1 4 STORE_FAST 0 (a) 3 6 LOAD_FAST 0 (a) 8 LOAD_ATTR 0 (remove) 10 LOAD_CONST 2 (0) 12 CALL_FUNCTION 1 14 POP_TOP 16 LOAD_CONST 0 (None) 18 RETURN_VALUE
從上面不難看出,整個 remove
操作被分成了好幾條指令,這就意味著在多線程情況下會出現錯亂的情況,試想一下,如果多線程下都去 remove
列表的話,并且不按照順序,很容易出現問題。
append
在最上面我們說到,list
的 append
操作是線程安全的,那么究竟是為什么呢?我們同樣來用 dis
查看一下
8 19 LOAD_GLOBAL 0 (a) 22 LOAD_ATTR 2 (append) 25 LOAD_CONST 2 (1) 28 CALL_FUNCTION 1 31 POP_TOP
這里顯然,append
也是有幾條指令,勢必在多線程執行的情況下也會發生交錯,但是對于多線程下我們操作 append
, 我們肯定也不會在乎這個時候 list
到順序問題了,所以我們說它的 append
是線程安全的
關于Python多線程下list的案例分析就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。