一文理解Python的全局解释器锁(GIL)

上一篇 / 下一篇  2024-04-02 11:17:03

  前言
  在Python中,全局解释器锁(Global Interpreter Lock,简称GIL)是一个重要的概念,它对Python解释器的并发执行模型产生了重大影响。本文将介绍GIL的概念、原理以及对Python多线程程序执行效率的影响,并附带详细的代码案例进行说明。
  什么是 GIL
  GIL是Python解释器中的一个互斥锁,它确保在同一时刻只有一个线程能够执行Python字节码。这意味着在多线程环境下,Python解释器无法同时利用多个CPU核心进行并行执行,因为只有一个线程能够执行Python字节码指令。
  GIL 的工作原理
  当Python解释器运行Python代码时,它会获取GIL,然后执行相应的字节码指令。其他线程想要执行Python字节码时,必须先获取GIL,但只有在当前线程释放GIL后才能获得。因此,只有一个线程能够在任意时刻执行Python字节码,这就是GIL的工作原理。
  GIL 的影响
  多线程
  尽管Python完全支持多线程编程, 但是解释器的C语言实现部分在完全并行执行时并不是线程安全的。 实际上,解释器被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。 GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势 (比如一个使用了多个线程的计算密集型程序只会在一个单CPU上面运行)。
  有一点要强调的是GIL只会影响到那些严重依赖CPU的程序(比如计算型的)。 如果你的程序大部分只会涉及到I/O,比如网络交互,那么使用多线程就很合适, 因为它们大部分时间都在等待。
  对于依赖CPU的程序,你需要弄清楚执行的计算的特点。 例如,优化底层算法可能要比使用多线程运行快得多。 类似的,由于Python是解释执行的,如果你将那些性能瓶颈代码移到一个C语言扩展模块中, 速度也会提升的很快。如果你要操作数组,那么使用NumPy这样的扩展会非常的高效。 最后,你还可以考虑下其他可选实现方案,比如PyPy,它通过一个JIT编译器来优化执行效率。
  多进程
  在 Python 中,GIL(全局解释器锁)只影响到了多线程,而不会对多进程产生直接的影响。多进程是通过创建不同的 Python 解释器来实现的,因此每个进程都有自己的独立 GIL,它们之间互不影响。
  如何解决 GIL 的缺点
  示例代码
  代码版本 Python 3.x
  如我们如何优化下列代码:
  # Performs a large calculation (CPU bound)
  def some_work(args):
      ...
      return result
  # A thread that calls the above function
  def some_thread():
      while True:
          ...
          r = some_work(args)
      ...
  使用多进程的方式
  如果你完全工作于Python环境中,你可以使用 multiprocessing 模块来创建一个进程池, 并像协同处理器一样的使用它,每个进程有独立的 GIL。
  # Processing pool (see below for initiazation)
  pool = None
  # Performs a large calculation (CPU bound)
  def some_work(args):
      ...
      return result
  # A thread that calls the above function
  def some_thread():
      while True:
          ...
          r = pool.apply(some_work, (args))
          ...
  # Initiaze the pool
  if __name__ == '__main__':
      import multiprocessing
      pool = multiprocessing.Pool()
  使用C扩展编程技术
  主要思想是将计算密集型任务转移给C,跟Python独立,在工作的时候在C代码中释放GIL。 可以通过在C代码中插入下面这样的特殊宏来完成:
  #include "Python.h"
  ...
  PyObject *pyfunc(PyObject *self, PyObject *args) {
     ...
     Py_BEGIN_ALLOW_THREADS
     // Threaded C code
     ...
     Py_END_ALLOW_THREADS
     ...
  }
  如果使用其他工具访问C语言,比如对于Cython的ctypes库,你不需要做任何事。 例如,ctypes在调用C时会自动释放GIL。

TAG: 软件开发 Python

 

评分:0

我来说两句

Open Toolbar