All Courses
Advanced Python

Python Global Interpreter Lock (GIL)

What is the GIL?

The Global Interpreter Lock (GIL) is a lock built into Python's interpreter that allows only one thread to use the interpreter at a time.

  • When a thread starts executing, it acquires the lock
  • No other thread can execute until the current thread releases the lock
  • This means Python threads run concurrently (taking turns) — never truly in parallel

The GIL is a software limitation of Python's interpreter — not a hardware limitation. Your CPU may have many logical cores, but Python's GIL prevents threads from using them simultaneously.


Impact on Python Programs

Threading model Possible in Python?
Concurrent (threads take turns) ✅ Yes
Parallel (threads run simultaneously) ❌ No — blocked by the GIL

If you create 4 Python threads, they run one at a time — not all 4 at once. This is why multi-processing (true parallelism) is not demonstrated in Python the same way it is in other languages.


Why Does the GIL Exist?

1. Shared Memory Between Threads

All threads in a Python process share the same memory space. This means: - A variable created in Thread 1 can be read and modified by Thread 2, 3, 4... - If multiple threads modify the same object at the same time, the results become unpredictable

Example of what can go wrong without the GIL: - Thread 1 thinks a list has 10 elements - Thread 2 deletes one element at the same time - Thread 1 now has inconsistent data — bugs and crashes follow

The GIL prevents this by ensuring only one thread runs at a time.

2. Performance — Avoiding Many Small Locks

The alternative to the GIL is placing individual locks on every shared object (this is what other languages do): - Every time a thread accesses a list, dict, or any object → acquire a lock - Every time it's done → release the lock - Acquiring and releasing locks costs time and reduces performance - Python tested this approach — it made the interpreter slower, not faster

The GIL is one single lock instead of thousands of small locks = simpler and faster for single-threaded use cases.

3. C Extensions

Python runs a lot of performance-heavy operations using C code extensions behind the scenes (e.g. sorting algorithms, mathematical operations). These C extensions were designed to work with the GIL. Removing the GIL would break many of them.

4. Reference Count / Garbage Collection

Python tracks whether objects in memory are still needed using a reference count: - Every variable pointing to an object increments the count - When a variable is deleted or reassigned, the count decreases - When the count reaches 0 → Python removes the object from memory

Without the GIL, multiple threads could modify the reference count of the same object simultaneously, leading to: - A reference count appearing to be 0 when it isn't → object deleted while still needed ❌ - A reference count appearing to be positive when it isn't → memory never freed (memory leak) ❌

The GIL ensures reference counting is always accurate.


GIL vs Per-Object Locks

Approach How it works Drawback
GIL (Python's choice) One lock on the entire interpreter No true parallelism
Per-object locks Individual locks on each shared resource High overhead; slower; very complex

Python chose simplicity and single-threaded performance over parallel capability.


Key Takeaways & Recap

Concept Summary
GIL A single lock that allows only one thread to execute Python code at a time
Effect Python threads are concurrent (not parallel)
Why it exists Shared memory safety, reference counting, C extension compatibility, performance
Hardware vs software Not a CPU limitation — a Python interpreter design decision
Other languages Most don't have a GIL; they use per-object locks or other mechanisms
Mutex The formal name for a lock like the GIL — covered more in later lessons