Python GIL


概述

GIL(Global Interpreter Lock)是什么东东?为什么当一些Pythoners在开发一些多线程操作的时候,都会有些很多疑问?多线程真的很糟糕吗?我该如何实现多线程并发操作?今天博主带你详细的介绍一下GIL。

GIL原理

由于Python是动态解释性语言,即解释运行。运行Python代码时都会通过Python解释器解释执行,Python官方默认的解释器是Cython,当然你也可以选择自己的Python解释器(PyPy,JPython),其中JPython就没有GIL的限制。在解释器解释执行任何Python代码时,首先都需要they acquire GIL when running,release GIL when blocking for I/O。如果没有涉及I/O操作,只是CPU密集型操作或者,解释器会每隔100 ticks(低级的解释器指令)就释放GIL(通过 sys.setcheckinterval来修改)。GIL是实现Python解释器(Cython)时所引入的一个概念。GIL不是Python的特性。

线程执行模型

我们先看一下Python下多任务线程执行模型,下面的图取自David Beazley大神,并且在他的个人网站中对GIL进行深度的解剖。如果想了解更深入的东西,可以去逛逛他的网站。

从上图中可以看出,这个是三个线程”协作式“执行,当Thread1执行时它获得GIL,其它线程一直在等待;当遇到I/O处理时,Thread1会释放GIL,Thread2得到GIL,Thread2开始运行,如此反复直到任务完成。当任一个线程正在运行时,它控制着GIL,并且在处理I/O(read,write,send,recv,etc.)时释放GIL。CPU密集型(不提供I/O操作)的线程作为特殊的情况被处理,即每运行100个低级的解释器指令进行检查并根据线程优先级进行释放/重新获取或者释放GIL。

我们来看一段代码:

import threading
import time

def count(n):
    while n>0:
        n-=1

if __name__ == "__main__":
    t1 = time.time()
    count(10000000)
    count(10000000)
    t2 = time.time()
    print t2-t1
    a = threading.Thread(target=count,args=(10000000,))
    a.start()
    b = threading.Thread(target=count,args=(10000000,))
    b.start()
    a.join()
    b.join()
    t3 = time.time()
    print t3-t2

# 输出结果
11.5187261105
18.4223148823

上述的例子是一个很典型的CPU密集任务,threading是Python高级别的线程库,Count只是普通的函数运行在一个主线程内。这就是为什么Python多线程的并不是真正意义上的多线程。Python的Thread是真实操作系统的Thread,两者没有差别。在Linux下是由pthreads实现的,而在windows下是由Windows threads实现的,并通过操作系统调度算法进行调度。为了充分利用CPU,python计算当前已执行了多少数量的指令达到阈值就会立即(100 ticks)来释放GIL。 我们分析一下程序问题: count函数里面主要做的是计算,I/O操作一直没有触发,那么就会一直等待知道100 ticks才会释放GIL。从release GIL到acquire GIL之间几乎是没有间隙的。所以在其他核心上的线程被唤醒时,大部分情况下主线程已经又再一次获取到GIL了。这个时候被唤醒执行的线程只能白白的浪费CPU时间,看着另一个线程拿着GIL欢快的执行着。然后达到切换时间后进入待调度状态,再被唤醒,再等待,以此往复恶性循环。

如何避免GIL影响

  • CPU密集型下的任务尽量采用多进程处理(multiprocessing).
  • 如果你不想使用Cython解释器,就没有这个限制,同样很多Cython的特性你也放弃了。
  • 利用 ctypes 绕过 GIL.ctypes会在调用C函数前释放GIL,可以通过ctypes和C动态库来让 python充分利用物理内核的计算能力。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++11基础学习系列一

    ---- 概述 C++11标准越来越趋于稳定和成熟,国外c++11如火如荼而国内却依然处于观望期。每当提到C++很多程序员都很抵触,特别是学术界的呼声更高一些。...

    BrianLv
  • VPC 深入浅出解析

    概述 今天给大家介绍一下博主最近做的一个项目:VPC.VPC(Virtual Private Cloud)虚拟私有云,租户可以在云中预置一个逻辑隔离分区,自己定...

    BrianLv
  • 深度学习笔记-深度学习实战

    BrianLv
  • Python Web学习笔记之为什么设计GIL

    GIL(global interpreter lock),全局解释器锁,是很多编程语言实现中都具有的特性,由于它的存在,解释器无法实现真正的并发。它也是 Pyt...

    Jetpropelledsnake21
  • Python的全局解释器锁(GIL)GIL是什么为什么会有GILGIL的影响顺序执行的单线程(single_thread.py)同时执行的两个并发线程(multi_thread.py)当前GIL设计的

    转一篇关于Python GIL的文章。 归纳一下,CPU的大规模电路设计基本已经到了物理意义的尽头,所有厂商们都开始转向多核以进一步提高性能。Python为...

    SeanCheney
  • 对GIL的一些理解

    python的代码执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运...

    步履不停凡
  • Jupyter Notebook最强指南,没有之一

    Python语言是一种强大而简洁的编程语言。据IEEE Spectrum消息,Python在2020年继续蝉联最受欢迎的编程语言第一名。对于刚接触Python的...

    朱小五
  • Kibana,Grafana——错误猎手,系统定海神针

    开发程序出现错误是一件很正常的事,即使有经验的程序员也是如此,关键是要及时发现并定位错误。

    用户2781897
  • 2018年春运火车票今天开售,手把手教你用python抢票回家过年……

    说明:本文编辑protream 和marvin的文章成篇 首先看看如何快速查看剩余火车票? 作者protream 原文:http://www.jianshu.c...

    企鹅号小编
  • 如何开发自己的搜索帝国之ES图形化Kibana安装与使用

      在如何开发自己的搜索帝国之Elasticsearch中已经介绍安装好了ES,下面就Kibana对ES的查询监控作介绍,就是常提到的大数据日志处理组件ELK里...

    欢醉

扫码关注云+社区

领取腾讯云代金券