全局解释器锁并不是由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.写入内存 三步,不是原子性的。
来源:CSDN
作者:cw437
链接:https://blog.csdn.net/cw437/article/details/104068139