Python Free Threading (No-GIL) — Core Concepts

What is free threading?

Free threading is an experimental CPython build mode (introduced in Python 3.13) that removes the Global Interpreter Lock (GIL). Without the GIL, multiple threads can execute Python bytecode simultaneously on different CPU cores, enabling true parallelism for CPU-bound workloads.

Why the GIL existed

The GIL solved a real problem. CPython uses reference counting for memory management — every object tracks how many references point to it. When two threads increment or decrement the same counter simultaneously without synchronisation, the count becomes corrupted, leading to memory leaks or crashes.

The GIL was the simplest solution: only let one thread run at a time. This made single-threaded code fast and every C extension automatically thread-safe. The cost was that multi-threaded Python programs couldn’t use multiple cores for computation.

How free threading replaces the GIL

Instead of one big lock, free threading uses several targeted techniques:

Biased reference counting

Each object has two reference counts — a fast thread-local count for the owning thread, and a slower atomic shared count for other threads. Since most objects are used by only one thread, the fast path dominates.

Per-object locks

Container mutations (adding to a dict, appending to a list) use lightweight locks on individual objects rather than a global lock. This allows different threads to modify different objects simultaneously.

Immortal objects

Frequently shared objects like None, True, False, and small integers are marked immortal — their reference count never changes, eliminating contention on the most commonly accessed objects.

Getting started

# Install free-threaded Python (example with pyenv)
pyenv install 3.13t

# Check that GIL is disabled
python3.13t -c "import sys; print(sys._is_gil_enabled())"
# Output: False

# Run your script
python3.13t my_parallel_script.py

When it helps

Free threading shines for CPU-bound parallel workloads:

import threading

def matrix_multiply(a, b, result, row):
    for j in range(len(b[0])):
        total = 0
        for k in range(len(b)):
            total += a[row][k] * b[k][j]
        result[row][j] = total

# Each thread computes one row — runs in parallel with free threading
threads = []
for i in range(len(matrix_a)):
    t = threading.Thread(target=matrix_multiply, args=(matrix_a, matrix_b, result, i))
    threads.append(t)
    t.start()
for t in threads:
    t.join()

When it doesn’t help

  • I/O-bound code — already runs concurrently with the GIL (the GIL is released during I/O)
  • Single-threaded code — runs 5-10% slower due to fine-grained locking overhead
  • Code using thread-unsafe C extensions — the extension may crash or produce wrong results

Library compatibility

As of 2026, the free-threaded ecosystem is growing:

LibraryStatus
NumPy 2.1+Supported
Cython 3.1+Experimental
pybind11 2.13+Experimental
DjangoNot yet
FlaskNot yet
Most pure Python codeWorks

C extensions must explicitly declare thread safety. If they don’t, Python re-enables the GIL when they’re imported — a safety net that prevents crashes.

The transition plan

The Python Steering Council laid out a phased approach:

  1. Python 3.13 — experimental, separate build
  2. Python 3.14-3.16 — stabilisation, ecosystem adoption
  3. Future — free-threaded becomes the default; GIL build becomes optional, then removed

Common misconception

“Free threading makes all Python code parallel automatically.” It doesn’t. Your code still needs to use threads (or a parallel framework) explicitly. The difference is that now those threads can actually run simultaneously, whereas before the GIL serialised them.

The one thing to remember: Free threading trades a small single-threaded slowdown for the ability to scale across all CPU cores — it’s the most consequential change in Python’s 30-year history.

pythonconcurrencyfree-threadingnogil

See Also

  • Python 310 New Features Python 3.10 gave programmers a shape-sorting machine, friendlier error messages, and cleaner ways to say 'this or that' in type hints.
  • Python 311 New Features Python 3.11 made everything faster, error messages smarter, and let you catch several mistakes at once instead of stopping at the first one.
  • Python 312 New Features Python 3.12 made type hints shorter, f-strings more powerful, and started preparing Python's engine for a world without the GIL.
  • Python 313 New Features Python 3.13 finally lets multiple tasks run at the same time for real, added a speed booster engine, and gave the interactive prompt a colourful makeover.
  • Python Exception Groups Python's ExceptionGroup is like getting one report card that lists every mistake at once instead of stopping at the first one.