What is the Global Interpreter Lock (GIL) in Python?
Understand the Python GIL: what the Global Interpreter Lock is, why CPython needs it, how it affects threads vs multiprocessing, and how to work around it.
Expected Interview Answer
The Global Interpreter Lock (GIL) is a mutex in CPython that allows only one thread to execute Python bytecode at a time, so pure-Python code cannot run on multiple CPU cores in parallel within a single process.
The GIL exists because CPython's memory management (reference counting) is not thread-safe; the lock protects internal interpreter state from concurrent corruption. It is released periodically and during blocking I/O or inside C extensions, so threads still help I/O-bound workloads. For CPU-bound parallelism you use multiprocessing, C extensions that release the GIL, or alternative runtimes; note the GIL is a CPython implementation detail, not part of the Python language.
- Makes CPython reference counting thread-safe without per-object locks
- Keeps single-threaded code fast and the C API simple
- Threads still speed up I/O-bound work because the GIL is released during blocking calls
- Simplifies writing thread-safe C extensions
AI Mentor Explanation
A cricket pitch has one strip and only the batter on strike can face a delivery, no matter how many players wait in the pavilion. The GIL is that single strip: many threads exist, but only the one holding the lock executes bytecode, while the rest wait their turn to come on strike.
Step-by-Step Explanation
Step 1
Understand why it exists
CPython uses reference counting for memory; the GIL protects those counts from concurrent corruption without locking every object.
Step 2
See the effect on threads
Only one thread runs bytecode at a time, so CPU-bound threads do not scale across cores in a single process.
Step 3
Know when it releases
The GIL is dropped during blocking I/O, time.sleep, and inside C extensions that call Py_BEGIN_ALLOW_THREADS, letting other threads run.
Step 4
Pick the right tool
Use threading for I/O-bound work; use multiprocessing, numpy/C extensions, or async for CPU-bound parallelism.
Step 5
Know the exceptions
The GIL is a CPython detail; Jython, IronPython, and free-threaded (PEP 703) builds behave differently.
What Interviewer Expects
- A clear definition of the GIL as a mutex over bytecode execution
- The reason it exists: thread-safe reference counting in CPython
- The distinction between I/O-bound and CPU-bound workloads
- Knowledge of multiprocessing and C extensions as workarounds
- Awareness that the GIL is a CPython implementation detail, not the language
Common Mistakes
- Claiming Python threads run truly in parallel on multiple cores
- Saying the GIL makes all your code thread-safe (it does not protect your own data structures)
- Confusing the GIL with the language spec rather than the CPython implementation
- Reaching for threading to speed up CPU-bound loops
- Thinking multiprocessing shares memory the same way threads do
Best Answer (HR Friendly)
“The GIL is a lock inside standard Python that lets only one thread run Python code at a time. It keeps memory handling safe and simple, but means heavy number-crunching does not get faster with threads alone, so for that we use separate processes instead.”
Code Example
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def count(n):
total = 0
for _ in range(n):
total += 1
return total
N = 20_000_000
# Threads: the GIL serialises the loops, so ~no speedup
start = time.perf_counter()
with ThreadPoolExecutor(max_workers=4) as pool:
list(pool.map(count, [N] * 4))
print(f"threads: {time.perf_counter() - start:.2f}s")
# Processes: each has its own interpreter and GIL, so it scales
if __name__ == "__main__":
start = time.perf_counter()
with ProcessPoolExecutor(max_workers=4) as pool:
list(pool.map(count, [N] * 4))
print(f"processes: {time.perf_counter() - start:.2f}s")Follow-up Questions
- Why does the GIL help I/O-bound programs but not CPU-bound ones?
- How does multiprocessing sidestep the GIL, and what are its costs?
- How can a C extension release the GIL during heavy computation?
- What does PEP 703 (free-threaded CPython) change about the GIL?
- Does asyncio avoid the GIL, and how is it different from threading?
MCQ Practice
1. What does the GIL primarily protect in CPython?
The GIL serialises access to interpreter internals, chiefly reference counts, which are not thread-safe.
2. Which workload benefits most from Python threads despite the GIL?
The GIL is released during blocking I/O, so threads overlap waiting time for I/O-bound work.
3. Which is the correct way to achieve CPU parallelism in standard CPython?
Separate processes each have their own interpreter and GIL, so they run on multiple cores in parallel.
Flash Cards
What is the GIL? — A mutex in CPython that lets only one thread execute Python bytecode at a time.
Why does the GIL exist? — CPython's reference counting is not thread-safe; the GIL protects it without per-object locks.
When is the GIL released? — During blocking I/O, sleeps, and inside C extensions that allow threads.
How do you get true CPU parallelism? — Use multiprocessing, C extensions that release the GIL, or a free-threaded build.
Is the GIL part of Python? — No, it is a CPython implementation detail; other runtimes may not have it.