What is the GIL (Global Interpreter Lock) in Python?
Learn what the Global Interpreter Lock (GIL) is in Python, why CPython has it, its impact on threading vs multiprocessing, and the free-threaded future.
Expected Interview Answer
The Global Interpreter Lock (GIL) is a mutex in CPython, the reference Python implementation, that allows only one thread to execute Python bytecode at a time, even on a multi-core machine, which means threading in CPython does not give you true parallel CPU execution for pure-Python code.
The GIL exists mainly to simplify CPython's memory management, since reference counting (how CPython tracks when to free objects) is not thread-safe without a lock; rather than adding fine-grained locks everywhere, CPython uses one global lock around bytecode execution. Threads still take turns running periodically, so threading remains genuinely useful for I/O-bound work — network calls, file I/O, database queries — because the GIL is released while a thread waits on I/O, letting other threads run. For CPU-bound work, the GIL becomes a bottleneck, which is why CPU-heavy Python code typically uses multiprocessing (separate processes, each with its own GIL and memory space) or offloads to C-extension libraries like NumPy that release the GIL during heavy computation. As of Python 3.13, an official experimental free-threaded build (PEP 703) can run without the GIL, and it is expected to mature and eventually become the default in future releases, but as of mid-2026 most production deployments still run the standard GIL-enabled build.
- Simplifies CPython's internals (safe reference counting without fine-grained locks)
- Makes single-threaded code fast since no per-object locking overhead exists
- Threading still helps I/O-bound workloads because the GIL releases during I/O waits
- multiprocessing sidesteps the GIL entirely for CPU-bound parallelism
- PEP 703 free-threaded builds are actively removing this limitation for the future
AI Mentor Explanation
The GIL is like a ground with only one pitch available, so even with eleven bowlers warmed up, only one can bowl at any instant while the rest wait. This is fine when a bowler pauses to walk back to their mark, since another can step in during that gap, but it caps how much true parallel bowling the squad can do.
Step-by-Step Explanation
Step 1
What the GIL is
A single mutex in CPython ensuring only one thread executes Python bytecode at any instant.
Step 2
Why it exists
CPython's reference-counting garbage collector isn't thread-safe without locking; the GIL is a simple global solution.
Step 3
Impact on CPU-bound code
Multiple threads doing pure computation cannot run in true parallel; only one runs Python bytecode at a time.
Step 4
Why I/O-bound threading still works
The GIL is released while a thread blocks on I/O, so other threads can run during that wait.
Step 5
Workarounds
Use multiprocessing for CPU-bound parallelism (separate processes, separate GILs), or C-extensions like NumPy that release the GIL.
Step 6
The future
PEP 703 introduced an experimental free-threaded (no-GIL) CPython build, maturing across recent releases.
What Interviewer Expects
- Correctly states only one thread runs Python bytecode at a time in CPython
- Explains the reference-counting motivation behind the GIL
- Distinguishes I/O-bound threading (still useful) from CPU-bound threading (blocked by GIL)
- Knows multiprocessing as the standard workaround for CPU-bound parallelism
- Is aware of PEP 703 / free-threaded Python as an evolving solution
Common Mistakes
- Saying Python cannot do concurrency at all because of the GIL
- Confusing the GIL with a language-level limitation rather than a CPython implementation detail
- Not knowing the GIL releases during I/O waits, wrongly dismissing threading entirely
- Assuming NumPy/C-extension code is always blocked by the GIL
Best Answer (HR Friendly)
“The GIL is a lock inside Python's most common implementation that lets only one thread run Python code at a time, even on a multi-core computer. It doesn't stop Python from handling many tasks at once for things like network requests, but for heavy number-crunching, developers use separate processes instead of threads to get true parallelism.”
Code Example
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def cpu_bound(n):
total = 0
for i in range(n):
total += i * i
return total
N, WORK = 4, 20_000_000
start = time.perf_counter()
with ThreadPoolExecutor(max_workers=N) as ex:
list(ex.map(cpu_bound, [WORK] * N))
print("threads:", time.perf_counter() - start) # slow: GIL serializes CPU work
start = time.perf_counter()
with ProcessPoolExecutor(max_workers=N) as ex:
list(ex.map(cpu_bound, [WORK] * N))
print("processes:", time.perf_counter() - start) # faster: real parallel coresFollow-up Questions
- Why doesn't the GIL hurt performance for I/O-bound threaded programs?
- How does multiprocessing achieve real parallelism despite the GIL?
- What is PEP 703 and what does 'free-threaded Python' change?
- Why do libraries like NumPy release the GIL during heavy computation?
- Is the GIL a Python language feature or a CPython implementation detail?
MCQ Practice
1. What does the GIL prevent in standard CPython?
The GIL ensures only one thread executes Python bytecode at a time within a single CPython process.
2. For which workload does GIL-limited threading still provide real benefit?
The GIL is released while a thread waits on I/O, so threads can overlap I/O-bound waiting even though only one runs bytecode at a time.
3. What is the standard workaround for CPU-bound parallelism in CPython?
multiprocessing spawns separate OS processes, each with its own interpreter and GIL, achieving true parallel CPU execution.
Flash Cards
What is the GIL? — A mutex in CPython allowing only one thread to execute Python bytecode at a time.
Why does CPython have a GIL? — To keep its reference-counting memory management thread-safe without fine-grained locks.
Does the GIL block I/O-bound threading benefits? — No — the GIL releases during I/O waits, so threading still helps I/O-bound workloads.
Standard workaround for CPU-bound parallelism? — The multiprocessing module, since each process gets its own GIL.