Python之GIL

>GIL为何物

GIL(Global Interpreter Lock),也称为全局解释器,看下官方解释

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

主要意思为:

GIL是一个互斥锁,它防止多个线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的

>Python与GIL

Python的GIL只是CPython(Python解释器)的一个问题,那么Python又有哪些解释器,它们也存在和CPython同样的问题吗?那么什么又是解释器呢?

什么是解释器

我们写的代码计算机是如何识别的呢,计算机也拥有和人类相同的思维和语言吗?显然不是的;计算机只能识别机器指令语言也就是0和1,那么我们编写的程序计算机是如何识别的呢?这就是解释器的作用了,解释器将我们编写的Python代码翻译为机器指令语言,Python解释器本身也是个程序,它是解释Python代码的,叫做解释器.

Python解释器有哪些

  1. CPython: 官方默认版本,使用C语言开发,是Python使用最广泛的解释器,有GIL.
  2. IPython: IPython是基于CPython之上的交互式解释器,其它方面和CPython相同.
  3. PyPy: PyPy采用JIT(Just In Time)也就是即时编译编译器,对Python代码执行动态编译,目的是加快执行速度,有GIL.
  4. Jython: 运行在Java平台上的解释器,把Python代码编译为Java字节码执行,没有GIL.
  5. IronPython: IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码,没有GIL.

>GIL解决了Python什么问题呢

Python内部对变量或数据对象使用了引用计数器,我们通过计算引用个数,当个数为0时,变量或者数据对象就被自动释放

In [1]: import  sys                                                  

In [2]: count_var = "test1"                                         

In [3]: sys.getrefcount(count_var)                                  
Out[3]: 2

In [4]: add_var = count_var                                         

In [5]: sys.getrefcount(add_var)                                    
Out[5]: 3

这个引用计数器需要保护,当多个线程同时修改这个值时,可能会导致内存泄漏;SO,我们使用锁来解决这个问题,可有时会添加多个锁来解决,这就会导致另个问题,死锁;

为了避免内存泄漏和死锁问题,CPython使用了单锁,即全局解释器锁(GIL),即执行Python字节码都需要获取GIL,这可以防止死锁,但它有效地使任何受CPU限制的Python程序都是单线程.

>GIL对多线程Python程序的影响

程序的性能受到计算密集型(CPU)的程序限制和I/O密集型的程序限制影响,那什么是计算密集型和I/O密集型程序呢?

计算密集型(CPU)

高度使用CPU的程序,例如: 进行数学计算,矩阵运算,搜索,图像处理等.

I/O密集型

I/0(Input/Output)程序是进行数据传输,例如: 文件操作,数据库,网络数据等


测试下顺序执行单线程和并发执行多线程的效率

- 顺序执行单线程(single_thread.py)

import threading
import time

def test_counter():
    i = 0
    for _ in range(100000000):
        i += 1
    return True

def main():
    start_time = time.time()
    for tid in range(2):
        t1 = threading.Thread(target=test_counter)
        t1.start()
        t1.join()
    end_time = time.time()
    print("Total time:{}".format(end_time-start_time))


if __name__ == "__main__":
    main()

执行结果:

Total time: 11.299654722213745

- 并发执行两个线程(multi_thread.py)

import threading
import time

def test_counter():
    i = 0
    for _ in range(100000000):
        i += 1
    return True

def main():
    thread_array = {}
    start_time = time.time()
    for tid in range(2):
        t = threading.Thread(target=test_counter)
        t.start()
        thread_array[tid] = t
    for i in range(2):
        thread_array[i].join()
    end_time = time.time()
    print("Total time:{}".format(end_time-start_time))


if __name__ == "__main__":
    main()

执行结果:

Total time:13.7098388671875

GIL对I/O绑定多线程程序的性能影响不大,因为线程在等待I/O时共享锁.

GIL对计算型绑定多线程程序有影响,例如: 使用线程处理部分图像的程序,不仅会因锁定而成为单线程,而且还会看到执行时间的增加,这种增加是由锁的获取和释放开销的结果.

>可以去掉累赘GIL吗

有大佬试过,只能说结果不尽人意0 .0,等待着吧

>SO,如何处理Python中的GIL

  • 计算密集型程序
    • 使用多进程(什么是多进程呢,后续道来)
    • 使用其它语言(将计算密集程序放到其它语言中执行)
    • 替换解释器(可以自己尝试)
    • 等大神解决GIL0 .0
  • I/O密集型程序
    • 使用多线程
    • 使用多进程
    • 使用多进程+多线程

Referce

What is the Python Global Interpreter Lock (GIL)?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容