Python有GIL為什麼還需要線程同步?
Python 有GIL保證相關對象的同時操作,那為什麼還需要進行線程同步?是不是因為在虛擬機層面之上在多線程工作時還需要提供相關的鎖機制、隊列機制,這其中的原理是什麼?有其他類似的例子嗎? 還是說Python內部的GIL保證了一個變數的引用數量,但是當多線程使用同一資源時,例如sys.stdout,這個時候是需要線程同步來確保資源訪問不衝突,GIL不提供類似資源的保護嗎?
這在網上都說爛了. 不過我當初也思考了這個問題一會兒.
你自己想想看這個情景線程AB同時操作listlist的[0]初始值為0線程A 操作100次
list[0]+=1線程B 操作100次list[0]+=1在線程A 對於 list[0]進行操作時
list[0]為0, 還沒等線程A完成加一操作, 就被切換到線程B了在線程B 眼裡,list[0]還是為0, 於是執行加一操作.再切換回線程A, 繼續未完成的加一操作你發現了沒!!! 線程AB各對list[0]進行了加一,預期結果是2 但結果還是1
Python的list不是完全線程安全的.
所以加個線程鎖就完了.
話說為什麼, 有了線程鎖還需要GIL呢?因為, 有了GIL, 提供並發就變得很容易. 解釋器只要計算每個線程的運行時間就好了時間一到, 將這個線程凍結, 內存管理很簡單.等等, 你還是沒解釋, 如果我已經給線程上了鎖, 為什麼還是要被GIL限制?
一向符合人類直覺的Python, 有個很反直覺的機制.Py的變數a其實不是C系編譯語言的變數.Python維護著一個字典, 儲存著a和對應數值的指針.用某黑Python的大牛的話說, Python企圖用字典裝下世界..如果變成真多線程
對於這個字典的維護將會很複雜.多個線程真正同時操作一個字典, Python引以為傲的字典性能, 估計就沒那麼強了.就是說, Python字典的性能強大,是建立在線程不安全的基礎上.而字典在Python中的位置又是如此重要, 一個緩慢的字典, 會嚴重拖慢Python的解釋速度.多線程操作多個獨立字典. 那樣還是要同步.那為什麼不採用多進程呢? 這就是社區主流的看法.雖然理論上線程成本更低, 但是那樣代碼就改成面目全非了..GIL也只是相當於古時候單核CPU通過不斷的分配時間片來模擬多線程的方法而已,為什麼那個時候寫多線程也要用鎖?
https://www.youtube.com/watch?v=ph374fJqFPE
GIL 的作用是:對於一個解釋器,只能有一個thread在執行bytecode。所以每時每刻只有一條bytecode在被執行一個thread。GIL保證了bytecode 這層面上是thread safe的。
但是如果你有個操作比如 x += 1,這個操作需要多個bytecodes操作,在執行這個操作的多條bytecodes期間的時候可能中途就換thread了,這樣就出現了data races的情況了。
比如這小傢伙就有很多條bytecodes:&>&>&> dis.dis(lambda x: x+1)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 RETURN_VALUE
GIL是全局解釋器鎖,GIL保證了在同一時間片下總有一個Python(CPython實現)線程在執行。所以即使是多進程,而是順序執行的。這樣多線程並發就變得沒有意義。
- 線程在GIL下是有執行的時間片的
- 在時間片內線程如果沒有成功對數據進行操作,那麼等到下一個時間片時,數據已經被別的線程修改了,那麼得到的數據就不是想要的數據了
- 線程的同步和互斥解決的是線程間數據的訪問正確性問題,而GIL是實現當前Python解釋器下只有一個線程在執行。兩個是不同的概念。
gil控制的是位元組碼, 鎖控制的是python代碼,粒度不一樣吧? 比如用鎖控制的代碼被編譯成101條位元組碼 那麼線程在執行這101條位元組碼的時候,cpu會被其他線程利用(python調度線程默認是100條位元組碼 調度一次)
——《Python源碼剖析》
很簡單,讀寫操作不是原子性的。線程鎖和cpu調度不是一個粒度上的
gil 是為了保護解釋器 讓python解釋器開發起來更加容易
推薦閱讀:
※像網路爬蟲、資料庫等方面多線程程序如何設置線程數?
※UDP socket能否被多線程同時調用sendto來發送數據?
※Linux 開發,使用多線程還是用 IO 復用 select/epoll?
※如何修改shared_ptr智能指針,讓他支持多線程?
※開發多線程的程序應該注意哪些問題?