Python中吉尔的使用详解

  

  

吉尔的全称为全局解释器锁,全局解释器锁。

  

<强> 1.1吉尔设计理念与限制
  

  

python的代码执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。即在任意时刻只有一个线程在解释器中运行。对python虚拟机访问的控制由全局解释锁吉尔控制,正是这个锁来控制同一时刻只有一个线程能够运行。

  

在调用外部代码(如C, c++扩展函数)的时候,吉尔将会被锁定,直到这个函数结束为止(由于期间没有python的字节码运行,所以不会做线程切换)。

  

在python中使用都是操作系统级别的线程,linux中使用的pthread,窗口使用的是其原生线程。

  

从上面的概述中可以直观的看出py在同一时刻只能跑一个线程,这样在跑多线程的情况下,只有当线程获取到全局解释器锁后才能运行,而全局解释器锁只有一个,因此即使在多核的情况下也只能发挥出单核的功能。

  

那么这样看起来py不给力啊,吉尔直接导致CPython不能利用物理多核的性能加速运行。那么为什么会有这样的设计?考虑到Guido van Rossum在创造python的时候,上世纪90年代,多核cpu完全属于不可想象的,现在由于硬件发展速度太快,程序编写就要考虑用尽cpu的全部性能,否则就要被淘汰,那么对于python同样也要如此。

  

上面主要说的是这种设计的劣势、下面再讨论它的优势。

  

吉尔的设计简化了CPython的实现,使得对象模型,包括关键的内建类型如字典,都隐式可以并发访问。锁住全局解释器使得其比较容易的实现对多线程的支持,但也折损了多处理器主机的并行计算能力。

  

但是不论标准的,还是第三方的扩展模块,都被设计成在进行密集计算任务时释放吉尔。另外还有在做IO操作时,吉尔总是被释放。对所有面对内建的操作系统C代码的程序来说,吉尔会在这个IO调用之前被释放,以允许其它的线程在等待这个IO的时候运行。如果是纯计算的程序,没有IO操作,解释器会每隔100次或每隔一定时间15女士去释放吉尔。

  

这里可以理解为IO密集型的python比计算密集型的程序更能利用多线程环境带来的便利。

  

<强> 1.2吉尔对线程执行的影响
  

  

多线程环境中,python虚拟机按照以下方式执行:

  
      <李>设置吉尔·李   <李>切换到一个线程去执行   <李>运行代码,这里有两种机制:   
        <李>指定数量的字节码指令(100个)   <李>固定时间15线女士程主动让出控制李   
      李   <李>把线程设置为睡眠状态李   <李>解锁吉尔·李   <李>再次重复以上步骤李   
  

上节说到python语言和程序一样要考虑用尽cpu的性能,下面在讨论py的应对方法。

  

python的应对方法很简单,在新的python3中依然有吉尔,原因大概有下几点:

  
      <李> CPython的吉尔·本意是用来保护所有全局的解释器和环境状态变量的,如果去掉吉尔,就需要更多的更细粒度的锁对解释器的众多全局状态进行保护。或者采用锁定算法。无论采用哪一种,要做到多线程安全都会比维系一个吉尔要难得多。另外改动的还是CPython的代码树及其各种第三方扩展也在依赖吉尔。   <李>进一步说,有人做过测试将吉尔去掉,加入更细粒度的锁。但是实践检测对单线程来说,性能更低。只有利用的物理cpu到一定数目后,性能才会比吉尔版本好。且现在绝大部分的python程序都是单线程的。   
  

然后最重要的还在于以下几个方面,简单来说就是py不改,一样能实现我们的需求。

  
      <李>自2.6引出的多进程标准库mutilprocessing,让多进程的python编写简化到类似多线程的程度,大大减轻吉尔带来的诸多不利。   <李>利用ctypes绕过吉尔:ctypes可以使py直接调用任意的C动态库的导出函数。所要做的只是用ctypes写python代码即可。而且,ctypes会在调用C函数前释放吉尔。
      李   
  

python中吉尔使得同一个时刻只有一个线程在一个cpu上执行,无法将多个线程映射到多个cpu上执行,但吉尔并不会一直占有,它会在适当的时候释放
  

        进口线程   数=0   def add ():   全球数   因为我在范围(10 * * 6):   数+=1      def - ():   全球数   因为我在范围(10 * * 6):   数-=1      thread1=threading.Thread(目标=添加)   thread2=threading.Thread(目标=-)   thread1.start ()   thread2.start ()   thread1.join ()   thread2.join ()   打印(count)

Python中吉尔的使用详解