PEP 779 – Criteria for supported status for free-threaded Python
- Author:
- Thomas Wouters <thomas at python.org>,Matt Page <mpage at python.org>,Sam Gross <colesbury at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Final
- Type:
- Standards Track
- Created:
- 13-Mar-2025
- Python-Version:
- 3.14
- Post-History:
- 13-Mar-2025
- Resolution:
- 16-Jun-2025
Note
The Steering Council accepts PEP 779 with a non-exhaustive list ofrequirements to be addressed during phase II. See theacceptance for details.
The acceptance ofPEP 703 (Making the Global Interpreter Lock Optional inCPython), asannounced by the Steering Council,describes three phases of development for the work to remove the GlobalInterpreter Lock. Phase I started early in the development of Python 3.13,and includes making the free-threaded (GIL-less) Python build available butexplicitlyexperimental. Phase II would make the free-threaded buildofficially supported but still optional, and phase III would make thefree-threaded build the default. Because of the number of unknowns at thetime, the criteria for moving to the next phase were left deliberately vagueat the time. This PEP establishes clear expectations and requirements formoving to Phase II, making the free-threaded Python build officiallysupported.
Note
Eagle-eyed readers may have noticed an overlap in authors of this PEP andthe Steering Council at the time of PEP 703 acceptance. The SC makeup hassince changed, but just to make it explicit: this PEP as proposed, whilebased on criteria set forth by the SC, does not come from the SteeringCouncil itself.
Whether to move forward withPEP 703 (as well as ultimately making it thedefault) is a question of whether the costs outweigh the benefits. Makingfree-threaded Python an officially supported build is important to signalthat we’re now at a stage where the design is finalised, the APIs are usableand stable, and we’re satisfied the performance and complexity cost is notprohibitive.
Moving to the “officially supported” stage is an important step towardsmaking free-threaded Python the default build, and eventually the only one.Before we can decide we’re ready to make it the default, we need a muchbetter picture of the costs and the benefits, and we can only get there ifmore of the Python ecosystem starts supporting free-threaded Python. Wecurrently have enough packages and tools supportingPEP 703 that it’sclear we’re on the right path, but not enough to make the final decision. Inaddition to giving the Python community time to make the changes necessaryto support free-threaded Python, we expect to use phase II to show clearbenefits in real-world applications, as well as clearly define the cost interms of performance, support burden, and ecosystem complexity.
In order for PEP 703 to be acceptable it should be desirable, stable,maintainable, performant (in CPU and memory), and ideally it should haveStable ABI so the same wheels can be used for free-threaded and with-GILbuilds.
- Desirability: from various experiments it’s very clear free-threadedPython has tremendous potential benefit. It’s not a simple drop-insolution – some code will have to be redesigned to make the most of thenew capability, as well as avoid performance pitfalls – but it canachieve higher performance, significantly lower latency and newthread-based functionality when embraced.
- Stability: the majority of the new API design is in 3.13, and is beingsuccessfully used to support free-threaded Python in a number ofthird-party packages (see for examplehttps://py-free-threading.github.io/tracking/). There’s been some moredevelopment in 3.14 to add more convenience functions, and to replaceAPIs that previously relied on the GIL for thread-safety, but we have nothad to break the 3.13 APIs for free-threaded Python.
- Maintainability: the majority ofPEP 703’s design is relativelysimple, with most complexity hidden away behind CPython’s existing CAPIs. The implementation details of, for example, lockless list and dictAPIs,which rely on QSBR,anddeadlock-avoiding critical sections,may be complex and difficult to get right, but gives us easy to use APIswithout too many pitfalls. Making more of CPython free-threading-safe isa relatively simple process, although we do probably need moredocumentation on the basic guarantees the new APIs provide(https://github.com/python/cpython/issues/128642).
- Performance: the performance penalty on linear performance, comparing afree-threaded build against a with-GIL build, as measured by thepyperformance benchmarks (for example as run byMicrosoft’s FasterCPython team,orMeta’s Python Runtime team),is currently around 10% (except on macOS, where it’s more like 3%). Wehave a few more PRs in flight that should get us comfortably below 10% onLinux and Windows.
- Memory use. Exact numbers vary because of the different gc moduleimplementation, but free-threaded Python currently sees about 15-20%higher memory use (geometric mean, as measured by pyperformance). Wehaven’t spent a lot of time trying to lower this yet, so we may be able topush this down further. Realistically, though, higher memory use is thecost of having efficient, safe free-threading, and we are unlikely to getthis very close to the with-GIL build’s memory use without significantperformance cost.
- Stable ABI. Stable ABI support is mentioned by the Steering Council as apotential requirement for phase II. While having Stable ABI support wouldmake third-party package distribution a lot easier, there’s a bit of achicken and egg problem: we don’t know if the Stable ABI is good enoughif we don’t have packages that support free-threaded Python using it, andwe can’t remove things from the Stable ABI if we discover problems withthem. Given that phase II is meant to give the community time to adoptfree-threaded Python and provide feedback on APIs and ABIs, we’re notsure how strong a requirement the Stable ABI should be for phase II.
Specific criteria for making free-threaded Python officially supported(phase II), as we propose them:
- Acceptable performance. The Steering Council mentioned they expectedfree-threaded Python to be around 10-15% slower, although this was not ahard target. We are currently around 10% and don’t expect it to getslower, but for phase II (not the default flip), we propose 15% as a hard performance target.
- Acceptable memory use. This was not mentioned by the Steering Council andhasn’t seen much discussion. We propose a target of 20% (geometric mean,as measured by pyperformance) for phase II. For phase III, we’ll needinput from the community as to where the trade-off between memory and CPUperformance should end up.
- Proven, stable APIs. This is a difficult thing to measure, but we haveseen significant adoption of free-threaded Python with the existing APIs,and have not had to radically change any existing APIs to accommodatethem. We will probably end up adding some more convenience APIs forspecific use-cases in the future, but we believe we have proven theviability and stability of the APIs we have. We have not neededbreaking changes in new APIs, and we expect all future changesto followPEP 387’s change policy.
- Internal documentation. We have multiple Core Developers working onfree-threaded Python, including several who recently started working onfixing thread-safety issues in specific modules, but we probably need toshore up the introductory documentation for the internals offree-threaded Python. This should not be a problem to achieve for 3.14.
With these criteria satisfied, we believe Python 3.14 is the right time framefor phase II ofPEP 703.
(Note that these are requirements for entering phase IIonly. The decisionto make free-threaded Python the default (phase III) is very different, andwe expect it will revolve around community support, willingness, and showingclear benefit. That’s left for a future PEP.)
- Should the Stable ABI be a strong requirement for “supported” status of the free-threaded build?
This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.