Read first

The GIL is a single lock inside CPython (the standard Python). A thread must hold it to run Python bytecode, so in one process only one thread executes Python code at a time, even on a 16-core machine.

Why it exists

CPython manages memory with reference counts on every object. One global lock keeps those counts correct without putting a lock on every object, which made the interpreter simpler and single-threaded code fast.

What it means in practice

  • I/O-bound work is fine with threads. The GIL is released while a thread waits on the network, disk or time.sleep, so other threads run.
  • CPU-bound work does not speed up with threads. Use multiprocessing / ProcessPoolExecutor (separate processes, each with its own GIL), or libraries like NumPy that do heavy work in C and release the GIL.
  • Free-threaded Python. Python 3.13 added an optional build without the GIL (PEP 703), usually installed as python3.13t. It is opt-in, and some C extensions still need updates to support it.
import sys
gil = getattr(sys, "_is_gil_enabled", lambda: True)()
print("GIL enabled:", gil)   # True on a normal build

concurrency-vs-parallelism explains why this is a parallelism limit, not a concurrency limit.

Check yourself