Global Interpreter Lock (GIL)
這是一個用在python內的一個鎖。但它並不是 python 本身就存在的功能,而是 CPython 內建的功能。CPython同時是一個 interpreter 和 compiler,它將 python code 轉換為 bytecode 之後再執行它。而GIL的作用是確保只有一個 thread 可以被 Interpreter 控制和執行。
Why?
在了解為什麼需要GIL之前﹐首先需要了解 Python 的 Garbage Collection Alogrithm。當中有兩樣東西 — Reference Counting 和 Garbage Collector (gc module) 。
Reference Counting 對於 Python 非常重要,因為 Python 的 variable 其實是 Object 的一個 Pointer/Reference。如果 Variable 被複製,Object’s Count 會增加,如果 Variable 被刪除,Object’s Count 會減少。當一個 Object 的 Reference Count 等於 0 的時候,CPython 會自動放出 Object 佔有的 Memory。 Global Variable’s Reference Count 基本是不會 0 的直到 Process 完結,而 Local Variable 在離開 Function 時就會除去。
Garbage Collector 則是為了解決 Reference Counting 的一個問題,那就是 Reference Cycle。 當兩個 Objects 互相指向對方或者一個 Object 指向自己,它們的 Reference Count 永遠都不會 0 。它如何解決可以參考 Ref。
當兩個 Threads 不斷去增加或減少一個 Object 的 References,這樣會導致 Memory Leak 或發生錯誤。因此 GIL 就是為了防止這種情況出現,鎖住其他 Thread 只讓一個 Thread 運行。
Problems?
在單核的機內GIL 是沒有問題的。
但是在多核的情況則會出現問題。每一個 Thread 都有兩個動作得到 GIL 和釋放 GIL。當一個 CPU 1 的 Thread 1釋放了 GIL ,同時它叫醒在 CPU 2 的 Tread 2,但是當 Thread 2 打算得到 GIL 時,Thread 1 已又再得到了 GIL。因此 Thread 2 的申請會失敗而進入等待狀態。而在這種情況下,Multi-thread 的效果會比 Single-thread 更差。