Inside The Python GIL

首先Python的线程是操作系统原生线程的封装,线程调度也是依赖于操作系统的。

>>> What is a Thread?

>>> Thread-Specific State

Python解释器会保存当前执行线程的全局变量,为了避免这个全局变量被多线程访问,所以需要GIL.

>>> Thread Execution

/* Python/pystate.c */
...
PyThreadState *_PyThreadState_Current = NULL;

Python解释器没有自己的线程调度器,依赖于操作系统的线程调度。

>>> Thread Scheduling


GIL Behavior

每个线程在执行之前需要acuqire GIL, 执行一段时间片去release GIL. 每个时间片称为"check interval" 可以通过 `sys.setcheckinterval()` 来做修改。

Pasted-Image-20231225103546.png Pasted-Image-20231225104637.png

tick并不是按照指令和时间来计算的,更像是根据high-level op来计算的,单个tick没有办法中断。也就是说,如果一个操作属于一个tick, 一旦执行之后想要Ctrl-C中断是不可能的。

一旦开辟工作线程之后,主线程要做的事情就是响应信号(signal), 以及等待工作线程结束。在check期间,主线程调用信号处理程序,而其他线程只是release然后重新acquire gil. 解释器寄希望于OS在check期间可以调度到其他工作线程,不过这样会带来很多问题。


Signal Handling

一旦线程检测到有信号(signal)的话,那么就要开始切换回到主线程来处理信号的。但是注意前面"Thread Scheduling",因为Python是自己做线程调度的, 所以几乎没有办法主动地要求切换回到主线程, 只能是期待操作系统调度调度到主线程 。如果这个时候其他工作线程是CPU密集型的话,很大规律是没有办法 切换回主线程的,而一旦切换到工作线程又会立刻yield出去,结果就是整个系统几乎是不能工作的,而且信号也没有办法响应。

Pasted-Image-20231225104902.png

Frozen Signals


GIL Implementation

Pasted-Image-20231225104137.png