GIL (Global Interpreter Lock) 全局解釋器鎖
通常,Python 采用 PIL 解釋器鎖將應用程序進程,鎖定於一物理綫程基礎之上。
即使是多綫程 CPU,一個應用程序進程同時最多也隻能使用一個物理綫程。
軟件層麵可以實現多綫程,但 Python 仍基於一物理綫程。
要真正實現利用多物理綫程,軟件層麵可以使用 多進程 替換多綫程。
Python 解釋器的實現有很多,譬如 C 實現的 CPython、Java 實現的 Jython、Python 實現的 PyPy;其中使用最廣泛的是 CPython。
由於采用 C 實現 Python 解釋器需要處理復雜綫程安全和並發環境內存管理,為降低解釋器實現的復雜性,CPython 引入瞭 GIL (Global Interpreter Lock)。
當使用多綫程時,CPython 解釋器會創建 GIL,每個綫程在執行前會先獲取 GIL,阻止其它綫程的執行。
在下列情況中,正在運行的 Python 綫程會釋放自己的 GIL:
CPU 竟爭機製:Unix 係統使用時間片算法,微軟 Windows 係統使用搶占式算法。
CPython 解釋器會定期檢查 GIL 占用時間,若超過瞭某個閾值,會強製綫程釋放 GIL。
可以采用 sys.setswitchinterval() 設置時間間隔,采用 sys.getswitchinterval() 查看最小時間間隔。
CPython 綫程等待 I/O 時,會主動釋放 GIL。
GIL 是為方便 CPython 解釋器的實現而産生的,保證字節碼在執行過程中不會被打斷,但並不能保證 Python 程序是綫程安全的。譬如:
>>> def add_one(n): n += 1 >>> import dis >>> dis.dis(add_one) 2 0 LOAD_FAST 0 (n) 2 LOAD_CONST 1 (1) 4 INPLACE_ADD 6 STORE_FAST 0 (n) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>>
以上範例中的 2 是行號。
函數 add_one 中的 += 從代碼層麵來看是一條語句,但是采用 dis 翻譯成字節碼後,會被分成 INPLACE_ADD 和 STORE_FAST 兩條語句。
由於搶占機製的存在,在執行完 INPLACE_ADD 之後解釋器可能會執行彆的綫程,此時若彆的綫程內也修改瞭 n 的值,就會齣現並發安全性問題。
Unix 係統使用時間片算法,微軟 Windows 係統使用搶占式算法,調用物理 CPU 綫程。
當一 _thread 在使用某個物理綫程,而另一 _thread 也想使用此物理綫程,就會形成竟爭機製。
若産生的物理綫程竟爭機製時間較長 (3 秒以上) 且當前物理綫程資源被耗盡,就可能導緻應用程序異常、卡死,甚至崩潰。
不推薦以同步阻塞 (或 3 秒以下短時間 time.sleep() 休眠) 方式,實現自循環 _thread;因為很容易導緻其它 _thread,與其産生物理綫程竟爭機製。
另請參閱:
版權聲明: 本文為獨傢原創稿件,版權歸 樂數軟件 ,未經許可不得轉載。