Question presented to candidate: "What is the GIL in Python? Why does CPython have one, what does it mean for multithreaded programs, and if it only lets one thread run at a time, why do we still need locks?"
What a strong answer should cover:
- The GIL is a mutex inside CPython: only the thread holding it may execute Python bytecode, so one interpreter runs at most one thread of Python code at a time, even on many cores
- Why it exists: CPython's memory management (reference counts on every object) and much of its internals and C-extension ecosystem are not thread-safe; one global lock made them safe simply and keeps single-threaded code fast
- When it is released: on blocking I/O and
time.sleep, inside C code that opts out (Py_BEGIN_ALLOW_THREADS, used by many I/O and number-crunching libraries), and every switch interval (5 ms by default,sys.getswitchinterval()) so other threads get a turn - Consequence: threads speed up I/O-bound work but not CPU-bound pure-Python work; use
multiprocessing/ProcessPoolExecutoror C extensions for CPU parallelism - The GIL does not make your code thread-safe:
counter += 1is several bytecodes and a switch can land between them, so shared state still needsthreading.Lock - Where it is going: per-interpreter GILs in 3.12 (PEP 684), an optional free-threaded build in 3.13 (PEP 703, experimental) that became officially supported in 3.14 (PEP 779)
Clarifying questions expected:
- Is the workload CPU-bound or I/O-bound?
- Which Python version and build (standard or free-threaded) will it run on?
Code / implementation expected: Optional β showing that counter += 1 is several bytecodes, or contrasting CPU-bound and I/O-bound threads.