Global Interpreter Lock
Aboutβ
The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) that allows only one thread to hold the control of the Python interpreter.
Due to the presence of GIL in CPython, only one thread can be in a state of execution at any point in time. The impact of the GIL isnβt visible to developers who execute single-threaded programs, but it can be a performance bottleneck in CPU-bound and multi-threaded code.
Why GIL?β
The GIL was introduced for multiple reasons as illustrated below
Memory Managementβ
Python uses reference counting for memory management, which means that objects created in python have a reference count variable that keeps track of the number of references that point to the object. When this count reaches 0, the memory occupied by this object is released.
This reference count variable needed protection from race conditions. If 2 threads decrease or increase its value simultaneously, leaked memory that is never released might occur, or even worse, the memory is incorrectly released while a reference to that object still exists.
While using individual locks on shared objects can prevent these issues, it introduces the risk of deadlocks and performance degradation due to repeated lock management.
The GIL solves these problems by ensuring that only one thread executes Python bytecode at a time, avoiding deadlocks and minimizing lock overhead. However, this effectively makes Python programs single-threaded for CPU-bound tasks, limiting true parallelism.
Simplicityβ
The GIL is simple to implement and was easily added to Python. It provides a performance increase to single-threaded programs as only one lock needs to be managed.
C libraries that were not thread-safe became easier to integrate. And these C extensions became one of the reasons why Python was readily adopted by different communities.
How it worksβ
Thread Schedulingβ
- The GIL allows one thread to execute Python bytecode at a time.
- Even if multiple threads are created, the GIL ensures that only one thread runs, while others wait for their turn.
- The GIL is periodically released (e.g., after 100 Python virtual machine instructions or after a certain amount of time).
Context Switchingβ
- To allow some level of concurrency, the Python interpreter periodically releases and reacquires the GIL
- The GIL is released during I/O operations (e.g., file reads/writes, network requests) to allow other threads to run.