CPython的GIL

GIL是什么

In CPython, the global interpreter lock is a mutex held by the interpreter thread, that prevents multiple native threads from executing Python bytecodes at once (exactly one thread to execute at a time, even if run on a multi-core processor). This lock is necessary mainly because CPython’s memory management is not thread-safe.

        mutex: used to synchronize access to a resource, only one thread can acquire the mutex. It acts as a gate keeper to a section of code allowing one thread in and blocking access to all others.

GIL何时释放

一个进程可以包含多个线程,这些线程共享当前进程中的内存空间(独享栈,共享堆/静态变量/全局变量/文件...) ,这种特性就出现了线程不安全的概念,即多个线程同时使用一个空间,导致程序逻辑错误 ,常见的方式就是使用锁或信号量等机制来限制公共资源的使用。

在CPython中,每一个Python线程执行前都需要去获得GIL锁 ,获得该锁的线程才可以执行,没有获得的只能等待 ,当具有GIL锁的线程运行完成后,其他等待的线程就会去争夺GIL锁。

当一个线程遇到I/O任务(在进入I/O操作前)或执行到设定的ticks或达到超时时间,释放该全局锁,从而实现解释器的分时复用。

GIL是否意味着线程安全

GIL虽然从设计的出发点考虑到线程安全,但这种线程安全是粗粒度的线程安全(即语言层面本身维护着一个全局的锁机制,用来保证线程安全),不需要程序员自己对线程进行加锁处理(同理,细粒度就是指程序员需要自行加、解锁来保证线程安全,典型代表是 Java ), 因此在CPython中需要具体分析什么情况下需要或不需要加锁:

由于IO操作而主动释放GIL的情况是线程安全的(由于线程A的IO操作等待时间不确定,那么等待的线程B一定会得到GIL锁,称为“协同式多任务处理”),而由于解释器运行的ticks或时间达到设定值而释放GIL的情况是线程不安全的(线程A和线程B将同时竞争GIL锁。在同时竞争的情况下,实际上谁会竞争成功是不确定的,虽然python3优化使得B优先级高,称为“抢占式多任务处理”),此时需要考虑加锁或考虑该计算操作在python中是否为原子级(即方法本身是单个字节码,因此线程无法在执行期间释放GIL)。

为什么CPython才有GIL

This seems to be related to the CPython garbage collector using reference counting (the JVM and CLR don't, and therefore don't need to lock/release a reference count every time). 

The JVM (at least hotspot) does have a similar concept to the "GIL", it's just much finer in its lock granularity, most of this comes from the GC's in hotspot which are more advanced.In CPython it's one big lock (probably not that true, but good enough for arguments sake), in the JVM it's more spread about with different concepts depending on where it is used. 

Without the lock, even the simplest operations could cause problems in a multi-threaded program: for example, when two threads simultaneously increment the reference count of the same object, the reference count could end up being incremented only once instead of twice.

What's more, Python was designed to be easy-to-use and a lot of extensions were being written for the existing C libraries whose features were needed in Python. To prevent inconsistent changes, these C extensions required a thread-safe memory management which the GIL provided. C libraries that were not thread-safe became easier to integrate with GIL.

Reference

互斥锁、条件锁、读写锁及自旋锁

猜你喜欢

转载自blog.csdn.net/qq_34276652/article/details/119532208
GIL