GIL

Python 运行流程

  • 编译成字节码
  • 解析器读取字节码 执行指令

全局解释器锁

保证同一时刻只有一个线程对共享资源进行存取

线程切换

协同式多任务处理

一个线程无论何时开始睡眠或等待网络 I/O,其他线程总有机会获取 GIL 执行 Python 代码。这是协同式多任务处理。

当一项任务比如网络 I/O启动,而在长的或不确定的时间,没有运行任何 Python 代码的需要,一个线程便会让出GIL,从而其他线程可以获取 GIL 而运行 Python[线程主动出让GIL]。这种礼貌行为称为协同式多任务处理,它允许并发;多个线程同时等待不同事件。

抢占式多任务处理

如果一个线程不间断地在 Python 2 中运行 1000 字节码指令,或者不间断地在 Python 3 运行15 毫秒,那么它便会放弃 GIL,而其他线程可以运行。

当解释器通过字节码时,它会定期放弃GIL,而不需要经过正在执行代码的线程允许,这样其他线程便能运行

diff 程序主动 系统主动

  • 协作式多任务处理 下一个进程被调度的前提是当前进程主动放弃时间片;
  • 抢占式多任务处理 操作系统完全决定进程调度方案,操作系统可以剥夺耗时长的进程的时间片,提供给其它进程。

线程安全

Python中的线程安全 许多 Python 操作是原子的

尽管有 GIL,你仍然需要加锁来保护共享的可变状态, 始终围绕共享可变状态的读取和写入加锁。毕竟,在 Python 中获取一个 threading.Lock 是廉价的

使用线程进行并发 I/O 操作,在进程中进行并行计算