GIL
先声明一下,原本没打算写这么多,但是写着写着发现,需要解释的东西太多了,一个套一个,其实我现在总结的这一版还是没有完全到每一个细节,但是我想靠这些应该差不多了。我想了一下大概还有两个没讲,1.为什么还用GIL 2.垃圾回收机制
什么是GIL?
GIL是cPython解释器的特有技术术语,中文为全局解释器锁。因为在创建Python的时候只考虑到单核的cpu
GIL的功能?
GIL的功能就是:在执行Python线程的时候,先锁住自身线程,实现同一时间只允许执行一个进程。
解决多线程之间数据完整性和状态同步的最简单方式就是加锁。 最重要的是能够帮助cpython解决其在内存管理中存在的线程不安全的问题。
GIL的运行方式?
1.某个线程拿到GIL
2.该线程执行代码,直到达到了check_interval(Python2中,check_interval是当前线程遇到io操作或者ticks计数达到100,Python3中是执行时间达到阀值15毫秒)
3.cpython让当前线程释放GIL
4.所有线程开始竞争GIL
5.竞争到GIL锁的线程,又开始从第一步开始
GIL存在对程序或者进程有什么影响?
由于Python线程的这种特性,导致Python在使用多线程进行处理多任务计算的时候,不能实现真正的并行操作;但是由于cpu的分片机制,会在运行一个线程一段时间后,切换到另一个线程(时间很快,感觉不到),从而达到伪并行的效果
为什么还需要GIL?
这和cpython的底层内存管理有关。cpython使用引用计数来管理内存,所有的Python脚本中创建的实例,都会配备一个引用计数,来记录有多少个指针来指向它。当实例对象的引用计数值为0的时候,会自动释放其所占的内存。
假如两个线程同时引用同一个变量,会造成引用计数的条件竞争,导致引用计数只增加1(实际应该增加2),这就有可能导致在第一个线程结束后,引用计数减1,正好达到释放内存的条件(引用计数为0),在当第二个线程再次访问变量的时候,无法找到有效的内存了。但是使用了GIL就可以避免这种问题,在第一个线程申请使用变量的时候,先加锁,当第二个线程使用的时候,第一个线程先释放锁,第二个线程同时加锁,就避免了变量的引用计数减少的情况
为什么Python线程会主动释放GIL?
前面讲到Python线程在执行前,会先上锁。如果不释放锁(也就是GIL)不就永远不会实现多线程,别的线程永远没有机会。这就涉及到cpython的另一个机制:间隔式检查,cpython会轮询检查线程GIL锁的情况,每隔一段时间,cpython就会强制当前线程去释放GIL,这样别的线程就可以执行了