← Back to Python

GIL — What It Is and What It Protects

PythonSeniorpython

The Question

What is Python's GIL, what does it protect, and what are its limitations?

What a Strong Answer Covers

  • mutex in CPython
  • "protects reference counting
  • "does NOT protect user code
GIL — What It Is and What It Protects diagram

Senior-Level Answer

The Global Interpreter Lock (GIL) is a mutex inside CPython that ensures only one thread executes Python bytecode at any given moment. It is not a feature of the Python language itself but an implementation detail of CPython, the reference implementation.

The GIL exists primarily to protect CPython's memory management system. CPython tracks object lifetimes using reference counting -- every object has a refcount field that is incremented when a new reference is created and decremented when one is released. When refcount reaches zero, the object is deallocated. Without the GIL, two threads could simultaneously increment or decrement the same refcount, corrupting it and causing either memory leaks or premature deallocation (use-after-free). Making every refcount operation thread-safe with fine-grained locking would be technically possible but would add significant overhead to every object creation and deletion. The GIL is a coarser, simpler solution.

The practical implications are significant. For CPU-bound workloads -- numerical computation, string processing, pure Python loops -- using threads does not give you parallelism. Multiple threads compete for the GIL, so only one runs at a time. The correct tool for CPU-bound parallelism in Python is the multiprocessing module, which spawns separate processes that each have their own GIL and Python interpreter, achieving true parallelism across CPU cores.

For I/O-bound workloads, threads remain useful. The GIL is released while a thread waits for I/O -- for example, during a network request or disk read. While one thread waits, others can run. This is why frameworks like Django historically used threading for concurrent request handling.

In Python 3.13, CPython added experimental support for running without the GIL (PEP 703, free-threaded mode). This required atomic refcounting and fine-grained locking throughout the interpreter. It is not yet the default and comes with performance trade-offs in single-threaded code.

What Separates a 2/3 from a 3/3

2/3 — Passing but Incomplete

Candidate knows the GIL prevents true parallelism for CPU-bound code and that I/O-bound threads still benefit, but cannot explain why the GIL exists (reference counting) or what exactly it protects.

3/3 — Strong Answer

Candidate explains reference counting as the root cause, distinguishes CPU-bound vs I/O-bound behavior clearly, describes multiprocessing as the right tool for CPU parallelism, and mentions GIL release during I/O and the direction toward free-threading in Python 3.13.

Common Mistakes

  • Saying the GIL prevents all multithreading -- it prevents parallel CPU execution, but I/O-bound threads still benefit from concurrency
  • Not knowing why the GIL exists -- saying it prevents race conditions without connecting it to reference counting
  • Forgetting that the GIL is a CPython implementation detail -- Jython and IronPython have no GIL
  • Claiming asyncio eliminates the need to understand the GIL -- asyncio is single-threaded cooperative concurrency, a separate concern

Follow-Up Questions

  • How does multiprocessing bypass the GIL? — Each subprocess gets its own Python interpreter and GIL, so they run in parallel on separate CPU cores.
  • Does the GIL get released during C extension calls? — It depends on the extension -- NumPy and many I/O extensions explicitly release the GIL using Py_BEGIN_ALLOW_THREADS to allow parallelism.
  • What is PEP 703? — PEP 703 adds a compile-time option to build CPython without the GIL using atomic reference counting and per-object locking. Python 3.13 ships this experimentally.
  • When would you still choose threads over multiprocessing in Python? — Threads have lower overhead (shared memory, faster creation) and are better for I/O-bound work or when shared mutable state is needed and carefully synchronized.

Related Questions

  • ThreadPoolExecutor & ProcessPoolExecutor
  • Decorators — Under the Hood
  • Generators & yield
  • Context Managers
  • LEGB Rule

Can You Explain This Cold?

Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.

Get Graded — Free Assessment
GrindQuestionsAITechnical interview assessment
TermsPrivacyAbout