October 2024, Revisited: Python 3.13 and the Beginning of the GIL Endgame
Eric Greene June 11, 2026This post is part of our Three-Year Retrospective series: thirty-six posts, one per month, looking back at what actually mattered in software engineering. This one covers October 2024.
Python 3.13 landed on October 7, 2024, and for once the headline feature wasn't syntax. Tucked behind a genuinely nicer interactive REPL and better error messages were two experimental builds that pointed at Python's long-term future: a free-threaded CPython without the Global Interpreter Lock (PEP 703), and a just-in-time compiler (PEP 744). Neither was on by default. Both announced that the two oldest complaints about Python — the GIL and raw speed — were finally being addressed in the interpreter itself rather than worked around.
Free-threading: the GIL becomes optional
For over three decades, the GIL guaranteed that only one thread executed Python bytecode at a time. It made CPython's memory management simple and single-threaded code fast, and it made threading useless for CPU-bound parallelism — hence the entire ecosystem of workarounds: multiprocessing and its pickling tax, C extensions releasing the GIL, async for I/O concurrency.
Python 3.13 shipped a separate build — python3.13t — with the GIL removed. The implementation, driven by Sam Gross's years-long effort, replaced the global lock with fine-grained locking, biased reference counting, and deferred reference counting. The honest 2024 status report: it worked, real multi-threaded speedups on multiple cores were demonstrable, and there were two big caveats. Single-threaded code paid a measurable performance penalty, and the C extension ecosystem — NumPy and everything downstream of it — needed to be rebuilt and audited for thread safety before any of it was production-advice. PEP 703's acceptance had been explicitly conditional: free-threading would prove itself in phases or be rolled back. The first step of every experiment that autumn was checking which build you were actually on:
import sys
import sysconfig
# True only on the free-threaded build (the python3.13t binary)
free_threaded = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
# Even on python3.13t, the GIL can be re-enabled at runtime
gil_active = getattr(sys, "_is_gil_enabled", lambda: True)()
print(f"free-threaded build: {free_threaded}, GIL enabled: {gil_active}")The JIT: modest numbers, important architecture
The experimental JIT used a copy-and-patch design: precompiled machine-code templates for bytecode operations, stitched together at runtime — much cheaper to build and maintain than a traditional optimizing JIT. The 2024 performance numbers were deliberately unimpressive, roughly neutral to single-digit gains. The point wasn't speed yet; it was that CPython finally had the infrastructure for machine-code execution, building on 3.12's tier-two interpreter work, with optimization headroom to grow into across releases.
What else mattered in 3.13
The features people actually touched daily: a new interactive shell (borrowed from PyPy) with multiline editing and colored tracebacks, error messages that kept getting more helpful, and the completed removal of the PEP 594 "dead batteries" — nineteen crusty standard-library modules gone. Our advice to teams at the time was unglamorous and correct: upgrade to the standard 3.13 build for the quality-of-life wins, experiment with python3.13t to learn the model, and don't ship it.
The more interesting exercise we ran in courses that winter: take a CPU-bound workload, run it under the free-threaded build with a thread pool, and watch all your cores light up from plain threading code. After decades of telling students "threads don't do that in Python," watching the old rule break in front of a class never got old.
Looking back from June 2026
The phased bet paid off. Python 3.14 in October 2025 promoted free-threading from experimental to officially supported — the single-threaded penalty shrank substantially, and the scientific stack spent 2025 shipping free-threaded-compatible wheels. The JIT kept maturing on schedule too. Nobody flipped a switch and made the GIL disappear from production overnight; instead, exactly as PEP 703's authors planned, the ecosystem is migrating one audited extension at a time, and "does it support free-threading?" is now a standard question on library READMEs. October 2024 was the month the endgame started.
If your team is building the foundations to take advantage of all this, our Intermediate Python course covers the concurrency model — threads, processes, async, and where free-threading changes the calculus — and High-Performance Python with Cython goes deep on the extension layer, where the real free-threading migration work happens.