As you may remember, PEP 703 (Making the Global Interpreter Lock Optional in CPython) was accepted for Python 3.13, as an explicitly experimental feature. The acceptance by the SC proposed several phases to flesh out the CPython design and create a support base in the community. A whole bunch of us – too many to reliably enumerate! – have been working on doing so, on both fronts, and it’s going quite well.
(Small side note, in case people forgot: I posted the SC acceptance I link to, but I’m no longer on the SC, and this PEP does not come from the SC. We did discuss this plan with the SC, though. Also, just to clarify: I was not working on free-threaded Python when the SC evaluated PEP 703, and I was in fact reasonably skeptical of it actually working out. I have since moved to Meta and started working on free-threaded Python, along with Matt and Sam and others, which has changed my mind considerably. This will absolutely work out.)
I think it’s time to move PEP 703 from “experimental” to “supported, but not the default”. I also think that this is something that needs broader support among Core Developers than just the people who’ve worked on it so far. A change like this is something that ultimately affects all parts of CPython, and just like the new interactive interpreter, the JIT or the standard library, it’s something we collectively, as a group, will have to maintain. We (the authors of the PEP, and I think most people working on free-threaded Python) think we’re ready, but it may be that others want specific things addressed before making their decision. We want to make sure we’re aware of everyone’s concerns while there’s still time to work on them.
So, PEP 779, pasted below [1], proposes the criteria to use to evaluate whether we’re ready to move PEP 703 to “supported”. Per the original SC acceptance, “supported” still does not mean it will definitely become the default. It means the foundational work in the interpreter is done, the APIs are stable, the result is very usable. While arguably not necessary for the “supported” phase, we also believe the performance is acceptable and fundamentally, the feature is proven to be very desirable. Once we, as a group, agree on the criteria for the “supported” phase we’ll see if we can satisfy all those criteria for Python 3.14, which is ultimately the SC’s call.
We have one major open question left in the PEP: whether we need Stable ABI support for free-threaded Python in order to promote it to “supported”. This presents a bit of a chicken-and-egg problem: how do we know the Stable ABI we’re designing is suitable for third-party users if there aren’t a lot of packages supporting free-threaded Python yet, and how do we convince packages to support free-threaded Python if CPython calls it experimental? (This is not an academic concern; folks working on adding free-threaded Python support to open-source packages have gotten pushback of that kind.) I believe we should try to get the Stable ABI done for 3.14 if we can, but it should not block making free-threaded Python supported.
WDYT?
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>
Status: Draft
Type: Standards Track
Created: 03-Feb-2025
Python-Version: 3.14
Table of Contents
Abstract
The acceptance of PEP 703 (Making the Global Interpreter Lock Optional in CPython), as announced by the Steering Council, describes three phases of development for the work to remove the Global Interpreter Lock. Phase I started early in the development of Python 3.13, and includes making the free-threaded (GIL-less) Python build available but explicitly experimental. Phase II would make the free-threaded build officially supported but still optional, and phase III would make the free-threaded build the default. Because of the number of unknowns at the time, the criteria for moving to the next phase were left deliberately vague at the time. This PEP establishes clear expectations and requirements for moving to Phase II, making the free-threaded Python build officially supported.
Note:
Eagle-eyed readers may have noticed an overlap in authors of this PEP and the Steering Council at the time of PEP 703 acceptance. The SC makeup has since changed, but just to make it explicit: this PEP as proposed, while based on criteria set forth by the SC, does not come from the Steering Council itself.
Motivation
Whether to move forward with PEP 703 (as well as ultimately making it the default) is a question of whether the costs outweigh the benefits. Making free-threaded Python an officially supported build is important to signal that we’re now at a stage where the design is finalised, the APIs are usable and stable, and we’re satisfied the performance and complexity cost is not prohibitive.
Moving to the “officially supported” stage is an important step towards making 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 much better picture of the costs and the benefits, and we can only get there if more of the Python ecosystem starts supporting free-threaded Python. We currently have enough packages and tools supporting PEP 703 that it’s clear we’re on the right path, but not enough to make the final decision. In addition to giving the Python community time to make the changes necessary to support free-threaded Python, we expect to use phase II to show clear benefits in real-world applications, as well as clearly define the cost in terms of performance, support burden, and ecosystem complexity.
Rationale
In order for PEP 703 to be acceptable it should be desirable, stable, maintainable, performant (in CPU and memory), and ideally it should have Stable ABI so the same wheels can be used for free-threaded and with-GIL builds.
- Desirability: from various experiments it’s very clear free-threaded Python has tremendous potential benefit. It’s not a simple drop-in solution – some code will have to be redesigned to make the most of the new capability, as well as avoid performance pitfalls – but it can achieve higher performance, significantly lower latency and new thread-based functionality when embraced.
- Stability: the majority of the new API design is in 3.13, and is being successfully used to support free-threaded Python in a number of third-party packages (see for example Compatibility Status Tracking - py-free-threading). There’s been some more development in 3.14 to add more convenience functions, and to replace APIs that previously relied on the GIL for thread-safety, but we have not had to break the 3.13 APIs for free-threaded Python.
- Maintainability: the majority of PEP 703’s design is relatively simple, with most complexity hidden away behind CPython’s existing C APIs. The implementation details of, for example, lockless list and dict APIs, which rely on QSBR, and deadlock-avoiding critical sections, may be complex and difficult to get right, but gives us easy to use APIs without too many pitfalls. Making more of CPython free-threading-safe is a relatively simple process, although we do probably need more documentation on the basic guarantees the new APIs provide (Free threading glossary of building blocks · Issue #128642 · python/cpython · GitHub).
- Performance: the performance penalty on linear performance, comparing a free-threaded build against a with-GIL build, as measured by the pyperformance benchmarks (for example as run by Microsoft’s Faster CPython team, or Meta’s Python Runtime team), is currently around 10% (except on macOS, where it’s more like 3%). We have a few more PRs in flight that should get us comfortably below 10% on Linux and Windows.
- Memory use. Exact numbers vary because of the different gc module implementation, but free-threaded Python currently sees about 15-20% higher memory use (geometric mean, as measured by pyperformance). We haven’t spent a lot of time trying to lower this yet, so we may be able to push this down further. Realistically, though, higher memory use is the cost of having efficient, safe free-threading, and we are unlikely to get this very close to the with-GIL build’s memory use without significant performance cost.
- Stable ABI. Stable ABI support is mentioned by the Steering Council as a potential requirement for phase II. While having Stable ABI support would make third-party package distribution a lot easier, there’s a bit of a chicken and egg problem: we don’t know if the Stable ABI is good enough if we don’t have packages that support free-threaded Python using it, and we can’t remove things from the Stable ABI if we discover problems with them. Given that phase II is meant to give the community time to adopt free-threaded Python and provide feedback on APIs and ABIs, we’re not sure how strong a requirement the Stable ABI should be for phase II.
Specification
Specific criteria for making free-threaded Python officially supported (phase II), as we propose them:
- Acceptable performance. The Steering Council mentioned they expected free-threaded Python to be around 10-15% slower, although this was not a hard target. We are currently around 10% and don’t expect it to get slower, 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 and hasn’t seen much discussion. We propose a target of 20% (geometric mean, as measured by pyperformance) for phase II. For phase III, we’ll need input from the community as to where the trade-off between memory and CPU performance should end up.
- Proven, stable APIs. This is a difficult thing to measure, but we have seen significant adoption of free-threaded Python with the existing APIs, and have not had to radically change any existing APIs to accommodate them. We will probably end up adding some more convenience APIs for specific use-cases in the future, but we believe we have proven the viability and stability of the APIs we have. We have not needed breaking changes in new APIs, and we expect all future changes to follow PEP 387’s change policy.
- Internal documentation. We have multiple Core Developers working on free-threaded Python, including several who recently started working on fixing thread-safety issues in specific modules, but we probably need to shore up the introductory documentation for the internals of free-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 frame for phase II of PEP 703.
(Note that these are requirements for entering phase II only. The decision to make free-threaded Python the default (phase III) is very different, and we expect it will revolve around community support, willingness, and showing clear benefit. That’s left for a future PEP.)
Open Issues
- Should the Stable ABI be a strong requirement for “supported” status of the free-threaded build?
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.
Source: https://github.com/python/peps/blob/main/peps/pep-0779.rst
paste with formatting was actually useful, I’m as surprised as you are! ↩︎