關於python的GIL全域性直譯器鎖的簡單理解
GIL是直譯器內部的一把鎖,確切一點說是CPython直譯器內部的一把鎖,所以要注意區分 這和我們在Python程式碼中使用執行緒鎖Lock並不是一個層面的概念。
1. GIL產生的背景:
在CPython解釋內部執行多個執行緒的時候,每個執行緒都需要直譯器內部申請相應的全域性資源,由於C語言本身比較底層造成CPython在管理所有全域性資源的時候並不能應對所有執行緒同時的資源請求,因此為了防止資源競爭而發生錯誤,對所有執行緒申請全域性資源增加了限制-全域性直譯器鎖。
言外之意,就是全域性直譯器就是為了鎖定整個直譯器內部的全域性資源,每個執行緒想要執行首先獲取GIL,而GIL本身又是一把互斥鎖,造成所有執行緒只能一個一個one-by-one-併發-交替的執行。
2. GIL什麼時候釋放
- 在當前執行緒執行超時後會自動釋放
- 在當前執行緒執行阻塞操作時會自動釋放
- 當前執行完成時
Python之父在觀點的最後部分說明 the language doesn't require the GIL -- it's only the CPython virtual machine that has historically been unable to shed it.
解釋來說就是Python語言和GIL沒有半毛錢關係。僅僅是由於歷史原因在Cpython虛擬機器(直譯器),難以移除GIL
3. 嚴重問題: 既然CPython解釋存在GIL是否意味每個執行緒在全域性變數就不用加Lock互斥鎖了呢?
這是一個嚴重錯誤的想法,為什麼使用者操作全域性資料還需要加Lock,因為GIL的釋放時機我們無法控制-操作非常可能並沒有完成,而不像Lock那樣我們用完才釋放(操作完整)。
正因為直譯器鎖的原因導致python的多執行緒說到底還是單執行緒,每個執行緒在執行的過程都需要先獲取GIL,保證同一時刻只有一個執行緒可以執行程式碼。所以就算使用多執行緒,其實還是一個執行緒在工作,但是由於在在IO操作等可能會引起阻塞,會暫時釋放GIL,執行完畢後,再重新獲取GIL,所以在進行IO等操作時的執行速度還是要比單執行緒速度快。
但是在執行計算密集型的程式時,需要使用CPU進行大量的計算,但由於GIL鎖的性質導致程式巡行中始終都是一個CPU進行計算,所以計算速度及其緩慢,執行此類的程式不推薦使用執行緒,有兩種方式解決:
- 使用多程序的方式,避免GIL鎖的約束
- 使用其他執行速度較快的語言模組,例如C語言