GIL下的多线程

1. GIL

  • GIL 是什么?

GIL 全称 Global Interpreter Lock,全局解释锁。存在于 CPython 解释器内,我们平时运行的 python 代码都是用 CPython 解释运行。在 CPython 解释器中,全局解释锁 GIL 是在于执行 Python 字节码时,为了保护访问 Python 对象而阻止多个线程执行的一把互斥锁

  • GIL 的作用和副作用

简单来说,CPython 解释器的内存管理不是线程安全的,即各个线程并行时,可能会造成数据相互污染。于是 GIL 规定同一时刻只能有一个线程进行执行,不管你数据污染与否,都给你一刀切,只能一个线程进行,这样就能保证内存管理的线程安全。

但正是由于 GIL 的存在,同一时刻只能有一个线程进行执行,因此 python 的多线程被称为假的多线程。

限于时代背景,当时还是流行单核 CPU,python 作者为了解决单核下线程安全问题,使用了最简单也是当时最佳的解决方案,也就是 GIL,没有考虑到未来多核CPU的快速发展后,多核CPU下的多线程效率大大提高,多线程应用场景越来越多。也经过几十年的发展,大量的代码和开发者以及严重依赖 GIL 来实现线程安全,重写的工作量过大,依然保留 GIL 方案。

2. GIL 原理

每个线程运行前,首先要获得 GIL,当线程任务运行完成,或者满足释放机制时,线程才会释放 GIL,给予其它线程机会获取 GIL 运行。每次 GIL 释放,其它线程都会被唤醒去一起竞争获得 GIL 的权限

GIL
  • 释放机制

python2: 当线程正执行I/O操作,或者计数器达到100个ticks的计数阈值时,释放 GIL。
python3: 当线程正执行I/O操作,或者计时器达到时间阈值时,释放 GIL。

线程执行 I/O
python2 100 ticks

3. 问题

(1) CPU 密集型任务,多线程相比单线程慢?

GIL的存在导致,无论多少个线程,都只有一个线程同时进行执行。多线程的每次 GIL 释放都会造成其它线程的唤醒,竞争,休眠,造成了线程颠簸,消耗了资源,降低效率,因此有可能更低。

(2) I/O 密集型任务,多线程提升效率很大?

I/O 密集型任务下多线程同样,并不是真正的多线程并行使得效率提升。当线程等待 I/O 操作,线程释放 GIL ,使得其它线程能利用好等待 I/0 的时间进行执行。所以 I/O 密集型任务下的多线程,在于提高了线程在 I/O 下的利用率。

(3)多核多线程比单核多线程快?

不管多少个核,有且只有一个线程同时运行,效率没有提升。

4. 总结

1. GIL 的作用保证了线性安全,有且只有一个线程同时进行执行。
2. CPU 密集型任务,多线程效率没有提升,可以使用多进程。
3. I/O 密集型任务,可以使用多线程提高效率,效率提升大小取决于 I/0 时长。

5. 参考

https://zhuanlan.zhihu.com/p/194990821

你可能感兴趣的:(GIL下的多线程)