Python技術分享:深入理解ThreadLocal變數的功能和使用
我們在進行Python多執行緒開發的時候經常會使用到變數,但全域性變數的變化影響到每一個執行緒,而區域性變數使用起來又非常麻煩,所以我們需要使用到ThreadLocal變數,下面小千就來給大家介紹這個ThreadLocal變數到底是什麼怎麼用?
ThreadLocal變數它本身是一個全域性變數,但是每個執行緒卻可以利用它來儲存屬於自己的私有資料,這些私有資料對其他執行緒也是不可見的。下圖給出了執行緒中這幾種變數的存在情況
全域性 VS 區域性變數
首先借助一個小程式來看看多執行緒環境下全域性變數的同步問題。
這裡我們建立了10個執行緒,每個執行緒均對全域性變數 global_num 進行1000次的加1操作(迴圈1000次加1是為了延長單個執行緒執行時間,使執行緒執行時被中斷切換),當10個執行緒執行完畢時,全域性變數的值是多少呢?
答案是不確定,簡單來說是因為 global_num += 1 並不是一個原子操作,因此執行過程可能被其他執行緒中斷,導致其他執行緒讀到一個髒值。以兩個執行緒執行 +1 為例,其中一個可能的執行序列如下(此情況下最後結果為1)
多執行緒中使用全域性變數時普遍存在這個問題,解決辦法也很簡單,可以使用互斥鎖、條件變數或者是讀寫鎖。下面考慮用互斥鎖來解決上面程式碼的問題,只需要在進行 +1 運算前加鎖,運算完畢釋放鎖即可,這樣就可以保證運算的原子性。
線上程中使用區域性變數則不存在這個問題,因為每個執行緒的區域性變數不能被其他執行緒訪問。下面我們用10個執行緒分別對各自的區域性變數進行1000次加1操作,每個執行緒結束時列印一共執行的操作次數(每個執行緒均為1000)
可以看出這裡每個執行緒都有自己的 local_num,各個執行緒之間互不干涉。
Thread-local 物件
上面程式中我們需要給 show 函式傳遞 local_num 區域性變數,並沒有什麼不妥。不過考慮在實際生產環境中,我們可能會呼叫很多函式,每個函式都需要很多區域性變數,這時候用傳遞引數的方法會很不友好。
為了解決這個問題,一個直觀的的方法就是建立一個全域性字典,儲存程式 ID 到該程式區域性變數的對映關係,執行中的執行緒可以根據自己的 ID 來獲取本身擁有的資料。這樣,就可以避免在函式呼叫中傳遞引數,如下示例:
儲存一個全域性字典,然後將執行緒識別符號作為key,相應執行緒的區域性資料作為 value,這種做法並不完美。
首先,每個函式在需要執行緒區域性資料時,都需要先取得自己的執行緒ID,略顯繁瑣。更糟糕的是,這裡並沒有真正做到執行緒之間資料的隔離,因為每個執行緒都可以讀取到全域性的字典,每個執行緒都可以對字典內容進行更改。
為了更好解決這個問題,python 執行緒庫實現了 ThreadLocal 變數(很多語言都有類似的實現,比如Java)。ThreadLocal 真正做到了執行緒之間的資料隔離,並且使用時不需要手動獲取自己的執行緒 ID,如下示例
上面示例中每個執行緒都可以透過 global_data.num 獲得自己獨有的資料,並且每個執行緒讀取到的 global_data 都不同,真正做到執行緒之間的隔離。
ThreadLocal 實現的程式碼量不多,但是比較難理解,涉及很多 Python 黑魔法,下篇再來分析。那麼 ThreadLocal 很完美了?不!Python 的 WSGI 工具庫 werkzeug 中有一個更好的 ThreadLocal 實現,甚至支援協程之間的私有資料,實現更加複雜,有機會再分析。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31548651/viewspace-2770226/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深入理解ThreadLocal及其變種thread
- 使用ThreadLocal變數的時機和方法thread變數
- 深入理解ThreadLocalthread
- Java技術分享之變數命名Java變數
- 深入理解java:執行緒本地變數 java.lang.ThreadLocal類Java執行緒變數thread
- 【技術分享】《深入理解Elasticsearch》讀書筆記Elasticsearch筆記
- 使用javap深入理解Java整型常量和整型變數的區別Java變數
- Java中的ThreadLocal深入理解Javathread
- 深入理解變數提升和函式提升變數函式
- 深入理解js的變數提升和函式提升JS變數函式
- 執行環境和變數物件的深入理解變數物件
- 深入理解冪等技術
- 『技術分享』-- 使用極光 IM 構建聊天功能
- JS中的變數賦值深入理解JS變數賦值
- 深入理解虛擬機器、容器和Hyper技術虛擬機
- 深入理解零拷貝技術
- Python面試題1:類變數在繼承中的深入理解Python面試題變數繼承
- Python的區域性變數和全域性變數使用解惑Python變數
- 深入理解[Future模式]原理與技術模式
- 一文深入理解快照技術
- 【Java核心技術卷】深入理解Java資料型別、變數 (擴充套件講解,結合Java資料型別變數套件
- 深入理解python中的類和物件Python物件
- 深入理解[觀察者模式]原理與技術模式
- 深入理解CAST和CONVERT提供的具體功能AST
- CSS 變數自動變色技術CSS變數
- 深入理解JavaScript的作用域與變數提升(hoisting)JavaScript變數
- CSDN社群乾貨技術分享:探尋技術進階之道(Python和AI)PythonAI
- 關於ThreadLocal變數的一個坑thread變數
- 深入理解Go系列一之指標變數Go指標變數
- 深入理解javascript系列(五):變數物件(VO)2JavaScript變數物件
- 深入理解javascript系列(四):變數物件(VO)1JavaScript變數物件
- git:rebase(變基)的使用和理解Git
- 數字技術變革:廣度、深度和溫度
- python爬蟲庫技術分享Python爬蟲
- python整數和變數Python變數
- python變數和引數Python變數
- ThreadLocal理解thread
- 理解ThreadLocalthread