Free-threading is the biggest change to Python concurrency in decades and affects how you write threaded code.
PEP 703 makes the GIL optional. Python 3.13 ships an experimental free-threaded build, usually installed as python3.13t (selectable in the official Windows and macOS installers, or built with --disable-gil). In 3.14 it becomes officially supported but still not the default.
In this build, threads execute Python bytecode in parallel on multiple cores, so CPU-bound pure-Python code can scale with threads, with no pickling and shared memory for free.
How to tell what you're running:
sys._is_gil_enabled()(3.13+) returns False when the GIL is actually off.sysconfig.get_config_var("Py_GIL_DISABLED")is 1 on a free-threaded build.
Caveats:
- Extensions must declare support. Importing one that doesn't re-enables the GIL at runtime (with a warning);
PYTHON_GIL=0or-X gil=0forces it off. - Single-thread speed is lower in 3.13 (about 40% overhead on the pyperformance suite), largely because the specialising interpreter is disabled; 3.14 narrows the gap considerably.
- Thread-safety: built-in types stay internally consistent using per-object locks, but races in your logic become much more frequent. Code that was "safe by accident" under the GIL will break. Use locks and queues properly.
Measure your own workload before switching.
Example
import sys, sysconfig, threading, time
free_build = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
gil_on = sys._is_gil_enabled() if hasattr(sys, "_is_gil_enabled") else True
print(f"free-threaded build: {free_build}, GIL enabled now: {gil_on}")
# standard build: free-threaded build: False, GIL enabled now: True
# python3.13t: free-threaded build: True, GIL enabled now: False
def cpu(n=3_000_000):
total = 0
for i in range(n):
total += i
return total
def run(threads):
t = time.perf_counter()
ts = [threading.Thread(target=cpu) for _ in range(threads)]
for x in ts: x.start()
for x in ts: x.join()
return time.perf_counter() - t
one, four = run(1), run(4)
print(f"4 threads take {four / one:.1f}x the time of 1")
# with the GIL: ~4x (serialised); free-threaded on 4+ cores: ~1x (parallel)Remember
- Python 3.13 has an experimental free-threaded build (python3.13t)
- Check with sys._is_gil_enabled() and the Py_GIL_DISABLED config var
- Expect slower single-thread code, extension caveats and more exposed races
Watch out for
- Assuming existing threaded code is correct on the free-threaded build because it never failed under the GIL.