通过学习,希望大家能够理解以下几个问题:
- Python 全局解释器锁到底是什么?
- Python 全局解释器锁如何影响多线程?
- Python 全局解释器锁应用场景?
1. Python GIL 影响
在讲解之前,我们需要先理解一点,Python 解释器本身是一个 C 程序,Python 代码是由这个 C 程序来解释执行。
在 Python 解释器中使用多线程方式实现多任务,则 Python 解释器程序内部就会创建两个系统线程分别去解释执行 Python 的函数代码。
这看起来一切都正常,可问题出现了。由于一些历史原因,导致 Python 解释器内部的两个线程在执行多个 Python 函数代码时,存在资源竞争问题。
Python 解释器内部创建的线程执行一个 Python 函数代码,需要读写解释器内部的一些全局数据,此时,如果另外一个线程也在读写这些全局数据,就会导致 Python 代码执行异常。
所以,Python 解释器内部的线程不得已在每次执行 Python 函数代码时都需要先加上互斥锁,防止自己正在使用的全局数据被意外篡改,导致任务函数执行异常。
例如:当 Python 解释器的线程执行任务函数1时,会对共享资源加锁,当函数执行完毕、或者发生 IO 阻塞等待时,才会释放这把锁。与此同时,由于全局数据被加锁,导致线程2无法拿到全局数据的使用权,则没有办法执行任务函数2。
至此,你会发现,由于这把锁的存在,导致多线程并不能真正实现多个任务函数并行,而是交替执行。这个互斥锁就是所谓的全局解释器锁。
2. Python GIL 场景
Python 的多线程无法真正实现并行,也就无法利用多核 CPU 资源,看起来很鸡肋。那么,Python 的多线程真的就一无是处了吗?
并不是的,对于在执行过程中,频繁需要等待的 IO 密集型任务,多线程还是有一定的优势的。前面我们提到,当线程碰到 IO 操作时,线程会自动释放锁,让其他的任务函数执行,避免浪费 CPU 的时间资源。
例如:当线程1执行的 Python 代码中碰到 IO 操作,则会马上释放锁,相当于放弃这次的执行,线程2就会马上获得锁,并获得执行机会,而不是默默地等待,浪费 CPU 时间。
此外,如果你的程序是需要长时间连续计算的任务的计算密集型任务,建议使用多进程,因为多进程不受全局解释器锁的影响,能够充分利用多核 CPU 资源提升计算效率。
多进程本质上是创建多个独立的解释器执行多个 Python 函数代码。
3. 小结
最后,我们来总结下:
- Python 全局解释器锁(Global Interpreter Lock,GIL)是一个存在于解释器中的互斥锁。
- 由于全局解释器锁的存在,使得 Python 多线程无法实现真正的并行计算。
- 对于 IO 密集型任务,Python 多线程具有一定的优势;
- 对于 CPU 密集型任务,Python 多进程更加适合。
注意:Python 全局解释器锁只存在于官方的 CPython 解释器中。
至此,关于全局解释器锁 就讲解完毕,希望对你有所帮助。