python中的全局解释器锁GIL

二次信任 提交于 2020-01-22 18:25:02

全局解释器锁并不是由python语言标准规定,而是由CPython解释器实现的

产生原因:

python的内存管理使用了引用计数的方法,而多线程同时操作一个变量时,引用计数可能出错导致内存泄露或者异常销毁,一个解决办法当然是加锁,但是python并没有采用,一个是频繁的加锁解锁影响性能,二是多个锁处理不好的话存在死锁的隐患,python干脆搞了一个全局的锁,GIL,任何python线程在执行之前必须获得这把唯一的解释器锁,避免了频繁加解锁和死锁。

同时也带来了问题,就是多线程无法真正利用多核。

刚才说道的是内存管理的线程安全,另外多线程间数据一致性也是问题,总之gil是为了解释器实现层面的线程安全,是当初的设计层面决定,很多人都认为这是一个烂设计,是一个历史遗留包袱。

 

1.python中的线程是不是操作系统内核线程,pthread?

答案是肯定的。python中的线程就是对操作系统内核线程的封装或者说是映射。一一对应。因此,python线程也是由操作系统内核进行调度的。进行调度的时机也是由操作系统来决定。

 

2.如果线程被操作系统调度,得到了CPU时间片,就一定会真正得到执行吗?

答案是否定的。

在解释器内部,涉及到线程执行的代码类似下面:

while True
    r=gil.require()
    if r:
        code_line_counter=0
        for code in thread_python_codes:
            exec_python_code(code)
            code_counter+=1
            if code_counter>100:
                break
        gil.release()
    #此时线程挂起当前线程,比如sleep(), 让出CPU,操作系统调度机会
    #另外IO操作时会释放gil

a.对于python单线程程序来说,确实,只要被调度获得了CPU时间片,那肯定会执行,因为gil被单线程独占,不会发生竞争

b.对于python多线程程序来说,

如果是单核CPU,同一时刻虽然也只有一个线程被调度,可是由于被调度时,可能其他线程并未释放锁,故也不一定可以真正被执行。

如果是多核CPU,当某个线程被调度得到CPU时间片时,可能其他线程并未释放锁,故不一定可以真正被执行。同一时刻仍然只能由一个线程能获取gil.

 

3.有了gil,我们是否可以放心的编写多线程程序,而不用担心线程安全了呢?

答案是否定的。一个常见的例子就是n+=1,python解释器执行的基本单位是编译出的python字节码,而n+=1这条python代码编译出的字节码,通过dis模块可知如下:

分为 a.加载  b.相加 c.写入内存 三步,不是原子性的。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!