PEP 779: Criteria for supported status for free-threaded Python

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


  1. paste with formatting was actually useful, I’m as surprised as you are! ↩︎

19 Likes

I have no real informed opinion on free-threading, but from prior work on measuring and improving PyPy’s memory use I’d suggest clarifying two things:

  • how should memory use be measured? as maximum rss?
  • is pyperformance actually a good benchmark suite for memory-heavy programs?
2 Likes

I’m not really involved in (using or maintaining) the C API, and until now I’ve done basically nothing with the free-threading build. One thing I would like to see as part of making free-threading “supported” is better information on what, precisely, this will mean for maintainers of pure Python code (and especially libraries). Can I confidently state that if my code currently works correctly, and is pure Python, then I support free-threaded Python? If not, then what do I need to do toget to a state where I can say that? Is running the test suite against a free-threaded build of Python sufficient, or do I need to add extra tests to explicitly check things in the presence of threads?

Furthermore, what (if anything) do I need to be aware of in code review for PRs to my project if I want to be sure that I’m including free-threading concerns in my review? To give a concrete example, pip currently does most of its work serially, but there is work going on to look at parallel downloads and parallel compilation of source code. Is there anything we should be doing to ensure that when we review such PRs, we’re prepared for a free-threaded build?

To be clear, I’m not asking for advice here, I’m saying that this sort of information should be documented, and easily accessible to interested project maintainers. If free-threading becomes supported in (say) Python 3.14, the “What’s New” should be able to link to a comprehensive section of the docs covering “preparing your project for free-threaded Python”. IMO, that’s an important part of moving to suppored status.

18 Likes

I agree with this. Many (most?) packages with C extensions don’t actually use the Stable ABI.

2 Likes

This is already documented for 3.13 in the HOWTOs and the “What’s New” included links:

3 Likes

That documentation isn’t very confidence-inducing, though. The free-threaded build “aims to provide similar thread-safety” (emphasis mine) and this is “not a guarantee of current or future behavior”.

I don’t know if it’s possible to authoritatively state “pure Python packages should always work in free-threaded Python” but making such a statement is one way to entice counter-examples to make themselves known. And I think that statement should be true to achieve supported status.

1 Like

OK. I think. That’s basically the same statement that I’ve heard previously, that essentially boils down to “Python code needs to do nothing and will support free-threaded builds without change”. There’s a proviso in there of “if you’re inadvertantly relying on undocumented guarantees the GIL provides, things may break for you”, but no help is given as far as how people should look for such assumptions, or what to do if they find them.

That’s OK, but it sort of feels unsatisfying. I want to challenge it by saying “so in all of the free-threading work, no Python code in the stdlib or 3rd party projects has needed to be changed?” But that suggests I don’t believe the statement in the documentation. And yet, the packaging ecosystem needed changes to recognise the new ABI tag, so clearly the existing statement doesn’t give the full picture…

Conversely, what benefits can pure-Python code gain from free-threading, and how can code be altered to get those benefits? “Your code could be improved by using free threading” is just as much of an impact as “your code doesn’t work in a free-threaded build”. That’s not the same question as I asked originally, but it’s also important.

Basically, what I’m saying is that IMO “supported” status needs to involve more than just technical changes. It needs documentation, including tutorial/explanatory articles covering how Python programmers can benefit from this new feature, what they should expect, how (if at all) it will impact existing code, both in terms of “will it still work” and “what opportunities do I now have to improve it”, and what pitfalls might exist. At the moment, all of the work is technical, getting the C API in shape and working with 3rd party C extensions to implement their support for free threading. That’s all vital work, but I don’t think we’re ready to call free threading “supported” if that’s all we’ve done.

I’m not criticising the state of the documentation. Getting the code working is absolutely the most important thing at the moment. But I do think that moving to “supported” status is when we should be starting to focus beyond the merely technical challenges, and start to look at other aspects of what’s needed for ordinary Python programmers to start using free-threaded builds “for real”.

10 Likes

I don’t think that’s true. A lot of Python’s thread safety guarantees have always been undocumented, and people got away with a lot - at least in part because of the GIL. Free threading takes away a safety net, but it doesn’t[1] guarantee to ensure that code which relied on undocumented behaviour will continue working. It’s hard enough ensuring that code relying on documented behaviour will still work.

But I do agree that a simple “if you were doing something undocumented, then tough” stance is unhelpful. Support should involve just that - support for people who need to work through this transition. We want them to fix their code (and be able to support it longer-term). Blaming them for relying on undocumented guarantees won’t achieve that.


  1. and shouldn’t, IMO ↩︎

3 Likes

What does a new stage for a build mean for our distributions? Historically, we’ve only really had “experimental” and “normal”[1] releases, and have rounded down to experimental when we want something to be non-default (for example, with the Windows ARM64 build, which is also suffering from tool/library developers not taking it too seriously).

With a new supported-but-not-default stage, what do we intend to release ourselves and how should users get it? What do we expect other distributors to release and how should users get it?

The eventual goal (as I understand it) is to eventually only have one standard release (i.e. one python command - not python and python-t forever), and I worry that formalising such a semi-experimental release design will encourage people to lock into it. e.g. we don’t want people hard-coding the t suffix everywhere without their own plan to remove it, or change behaviour based on just a version number and not a suffix.

Without a stronger definition of what this intermediate release design looks like, I’d prefer to just keep it under the “experimental” header and more actively promote to package developers “this means you”.[2] Creating a different kind of release feels like a technical distraction to solve a marketing problem.


  1. Or “non-experimental”… no better word presents itself to me right now, but maybe we have one. ↩︎

  2. I’m channeling the ARM64 experience here too, where I’ve literally had critical ecosystem dependencies say “we’ll worry about it when it’s not experimental”, to which I’ve had to reply “we’re waiting for you to support it first, so that users aren’t broken on day 1”. ↩︎

1 Like

I see your point, it’s just difficult for me to come up with something you can do in pure Python that would break in free-threading and wouldn’t be considered a bug[1]. I didn’t intend the statement to imply that undocumented behavior/implementation details are suddenly guaranteed to be stable.


  1. if all dependencies are compatible, and the thing works correctly with the GIL ↩︎

1 Like

Right now, cls.counter += 1 is atomic in cpython >=3.10 with the gil, isn’t that correct? The reasons for that are kind of spurious (gil is only released at certain bytecodes). But it still makes ‘not considered a bug with the gil’ too imprecise.

1 Like

(Deleting this, since others already pointed out the same issue.)

I have one concern about this.

I have recently started reading all the “new-issue” emails. Apart from a little bit of spam and lots of issues unrelated to free-threading, I have also seen quite a few reports about race conditions in C code using free threading (many filed by Sam).

I’m sure that Sam or others working on free-threading will fix these quickly, but it makes me worry for 3rd party extensions that have a large amount of C or C++ code – if they have things that need to be made thread-safe, they will surely encounter many similar bugs, especially once they start writing tests that really hammer the free-threading aspect. And they don’t all have Sam-level experts in finding and fixing such bugs.

This makes me worry that the whole project may be just too complex. I would rather suffer another year of experimentality, where we can deliberate carefully about the “forever” maintenance burden, not just for CPython, but for 3rd party C/C++/Rust (!) extensions, than commit in the rush before 3.14 beta 1 (less than two months away – May 6, about a week before the Language Summit where we might debate this more effectively in person).

14 Likes

Those are good questions, and for the purposes of this PEP I think we should use what we have available now, which is pyperformance’s memory reports. For the next phase, as the PEP mentions, we need to know what people actually care about, and then we need to figure out how to measure that. The pyperformance benchmarks measure fairly well how the pyperformance benchmarks use memory, so it’s not bad for seeing the impact of changes, but it doesn’t necessarily reflect what end users can expect to see.

We don’t have a better answer to that than (POSIX) threading sees in general, for many other programming languages, which is “eeeh, well, uuuhm” and – if you’re lucky – “maybe run this tool and see”. We don’t have tooling like ThreadSanitizer or Thread Safety Analysis like they’re available for C++ (yet), although those tools do work for extension modules.

We do have documentation that tries to answer these things, like Python experimental support for free threading — Python 3.13.2 documentation and https://py-free-threading.github.io/, although I’m sure they can use more work (also, @ngoldbaum mentioned to me that he’s going to try and address some of your questions there.) If people who aren’t familiar with free-threading yet would like to review those and tell us what they’re missing, that would be great :). I’ll add an item to the PEP about good user-facing docs, in addition to the internal docs, although the question is really how much this matters in order to be able to say “this feature is now stable and supported in CPython”.

I haven’t had to touch any Python code myself (other than writing tests), but I haven’t done most of the third-party work. Maybe @ngoldbaum or others from Quansight who’ve worked on that can comment.

The tricky thing with threads, of course, is that you don’t know if something is thread-safe until you discover it is not, by using it (heavily) from multiple threads at the same time. But it is the case that anything in Python code that relies on the GIL isn’t thread-safe, it just had a much lower likelihood of breaking because of the GIL. Would you count finding and fixing those kinds of issues as part of the work to support free-threading?

I think you know this, but I want to point it out explicitly for other readers: undocumented thread-safety guarantees are not guarantees. The GIL does not make Python code thread-safe, undocumented or otherwise. Any Python code that relies on the GIL is likely to already be subtly wrong, free-threading makes it more apparent.

I don’t think we’ve considered this at all. I assumed we would continue to do what we did, except remove mention of the feature as being ‘experimental’. For 3.14 it probably still needs to carry warnings about limited third-party support, not unlike the caveat we had to apply to the 64-bit Windows installer for a long time. Do you think we need to make it more prominent in the installers?

The problem is that we need people to actively test things, so they will need a way to invoke the free-threaded build. Whether we call it experimental or not, they will end up relying on the python-t versions. And the “experimental” phase, per the SC’s acceptance, was to solidify the API design and CPython’s implementation. We think we’re done with that, and we don’t want to make it seem to users that this can break in incompatible ways or suddenly vanish. Once it’s supported, rather than explicitly experimental, PEP 387 applies, etc.

Oh yes, that’s definitely the bulk of the work in extension modules. It’s not always easy, especially if you have complicated shared state. But for most of it, the fixes are relatively easy. It doesn’t require a Sam-level expert. I know, because I fixed some myself :joy: – but also, we have documentation, and a bunch of people fixing things in a whole bunch of projects, all the way to producing free-threaded wheels in some pretty complicated packages, like numpy. It’s definitely some work, but it’s at least somewhat of a paved path now.

Also, the existence of free-threaded Python does not force projects to fix their extension modules. When extension modules don’t declare they support free-threaded Python, they can still be used – they just re-enable the GIL when imported. That will matter to users of the package who do want to use it in a GIL-less free-threaded build, of course, but it’s not nearly as immediate a break as Python 3 was.

And just to tie it to this particular PEP, I do think we need to be clear in our messaging around free-threaded being “supported” in CPython: it does not mean users can expect third-party packages to work. Everywhere we talk about it, we need to be honest about what users can expect from the community in this. As mentioned in the SC acceptance, it will take time to migrate everything… but we have a solid, supported base to get that going, and we can have a nice gradual migration.

That is a fair concern, even if I don’t share it in this case. I think making it clear that PEP 387 applies to free-threaded Python is important for that reason, too: it’s not suddenly going away, but it’s not, at this point, a “forever” guarantee either. (The SC acceptance mentions this, too: in phase II, we can still roll it all back.)

As for the burden on third-party developers, the decision to support free-threaded Python is ultimately up to them. Whether we call it “supported” in CPython or not, work will continue to add free-threading support to more packages, because it really is a desirable feature. I think the question is whether we want to make guarantees to them about the stability of the implementation.

4 Likes

I believe this is very premature. Aside from a handful of hand-curated packages where highly capable people contributed that support, we basically have no degree of broader roll-out in the ecosystem. As a very concrete example, we’re still waiting for a free-threading-compatible release of Cython, which underlies a large number of very popular packages. People have been using alpha versions or commits from main so far, but we really haven’t gotten broad usage here.

:100: x2

In conda-forge, we believe that we’ll be able to start the migration for free-threading build in conda-forge sometime this spring – this will likely surface a large amount of issues. I had been keen to start this process earlier, but other people more deeply involved with the free-threading effort told me at the time that this was premature. As such, I’m quite surprised to see this proposal already.

Overall, I also think that the problems can be fixed, but on an ecosystem-level (i.e. outside of CPython) we’ve really only barely started to find out the impact of this. Given the following quote from the acceptance of PEP 703 (my bold)

we’re really not there yet. Sam et al. cannot clone themselves to support nogil builds for all projects across the ecosystem, so IMO we need the community to be able to handle this independently of the nogil luminaries, before we can talk about “enough community support”.

8 Likes

That’s certainly a concern. With so many 3rd party extensions, some of them will never be made free-threaded compatible and some of them will take a long time to get there. However, a huge amount of progress has already been made on popular libraries. See this status page: py-free-threading status tracking. Large and complex things like numpy, scipy and cython are pretty much working today.

Based on what I’ve seen, most of the free-threaded problems in extensions are straight-forward to fix. Having global state that is mutated is common, for example. Tedious work to fix those things but generally not tricky. There are some complicated ones, like interaction with Rust’s borrow checker or “poisoned” locks that take some deeper thinking to solve. Those kinds of tricky things are perhaps more likely to show up in “meta” extensions, like pyo3 or pybind11.

To find possible free-threaded issues, the ThreadSanitizer (TSAN) has been a great help. You don’t need a program or test case that provokes an actual data race, just a potential one. The TSAN warning then points out the line of codes in question and generally it’s pretty easy to fix. For extensions, usually the solution is to use a lock or to use a thread-local variable for the state.

Fixing data race issues in CPython itself can be harder. That’s because CPython is very performance focused and uses a number of different concurrency control mechanisms. It can be a challenge to understand how it all works. Most 3rd party extensions don’t need those “big guns”. They can usually do the simpler thing.

That does lead to perhaps the main concern with making free-threaded Python non-experimental. It will increase the burden of CPython maintenance. Extensions get to choose to opt-in to free-threaded support. CPython maintainers don’t have a choice as long as free-threaded is a possible build option. However, if it’s called experimental or not doesn’t really matter for the CPython maintainers, as long it exists they have to maintain it.

The name matters for 3rd party extension authors. If we keep calling it experimental then I think they could be well justified in not attempting to make their extensions compatible. After all, maybe it will go away again in a year or two. At this point, I see that as extremely unlikely. We do the Python community a disservice by being overly cautious (in addition to not being cautious enough). If your libraries support it, free-threaded 3.13 is already quite usable. Version 3.14 is going to be significantly better yet.

Even if Sam wins the lottery and moves to the private island, never to touch Python again, I’m quite certain that there is already a critical mass of developers to keep it working. And, once people are seriously using it on tasks that benefit from the concurrency it offers, they will demand it. The performance gains are just too large. Working around the GIL, while in theory possible, is just too painful.

It’s the “serious use” part that we are not quite there yet today on. It’s only in the last couple months that some popular 3rd party libraries got free-threaded support. It’s kind of similar to the 2-to-3 transition in that you can’t actually benefit from free-threading until all the modules you import support it. So that takes some time. It will take longer if extension authors think we are not serious about supporting the free-threaded build.

6 Likes

I suspect even more common is extensions that export their own object types where the instances of those types (implemented in C etc.) have mutable state. Nothing stops two different threads to share such an object and to start mutating it in both threads.

(I feel the need to call this out, because I don’t want people to believe that global mutable state is the main trigger for race conditions. If only it was that easy – you could do a quick audit for global mutable state and if you don’t have any you might think you were safe. Not so – you have to audit for all mutable state, no matter where it occurs.)

2 Likes

I’m a little concerned about the Stable ABI for free-threaded Python and getting it right:

For most extensions I think you really need some use of critical sections (which aren’t in the stable ABI, and may be an unpopular feature to add?), and the safer PyList_GetItemRef type accessors (which are in it, but only in recent versions). (I’m slightly unclear on whether people still plan to “backdate” Stable ABI support).

Essentially, I’d worried about the stable ABI being a source of thread-safety mess. From a Cython POV, we largely support the stable ABI, and independently largely work with free threaded Python (at least for its internal structures - the expectation is that users chose the thread safety they want for their own code). However trying to combine the two would definitely not be thread safe right now, and might not even be possible to fix (depending on what was in the stable ABI).

I’m sure you’re all aware of this though. But I wouldn’t rush to Stable ABI to meet some milestone.

3 Likes

What would be useful is a simple tool (perhaps just a script wrapping a grep invocation) that allows finding potentially dangerous uses of the C API in free-threaded mode.

In our case (PyArrow), we have a bunch of hand-written C++ code calling the C API for which an eyeball audit would likely miss potential problems (in addition to being tedious).

We have another potential problem in that we use the NumPy C API to access NumPy arrays and scalars, and it’s not obvious whether those APIs are themselves safe to use in free-threaded mode (NumPy arrays are not immutable, they can be resized and reallocated). Perhaps @ngoldbaum wants to elaborate here.

I’ll note that “pretty much working” does not imply they don’t have any thread-safety issues in free-threaded mode. Historically, I don’t think the NumPy and SciPy test suites exercise multi-threading a lot.

Yeah, but you do need some multi-threaded tests to surface those issues, and you need them to run long enough to give TSan a statistical chance of noticing something. MT tests are typically more difficult to write and longer to run [1], so that most developers don’t bother writing them.


  1. And TSan itself multiplies that by a non-trivial slowdown factor. ↩︎

2 Likes

This is reasonable for the areas that are covered by native/Python API, but I don’t think it extends to installation (including file layout, command name, sysconfig variables, and things like “what should build backends do”).

Due to the separate install for now, those are guaranteed to change, albeit back to how non-freethreaded Python works. At the very least, we should explicitly draw a line around the things we want to commit to at this stage and leave everything else outside of it. As a starting point, I’d suggest “public Python APIs and header files in Include and Include/cpython, excluding pyconfig.h” (as in, we’re not guaranteeing pyconfig.h will have the same values after it’s merged back in, which probably seems obvious but it isn’t to everyone).

I’m not hugely concerned about prominence in the installers (I’m hopefully retiring the Windows ones anyway, potentially on the same timeline :wink: ). But the people who will commit to the way things are now are largely the ones who are at least reading release notes and download pages.


More generally, provided this doesn’t affect the option for the SC to eventually decide against free-threading and remove all the changes, I think it’s fine to declare the APIs are stable. But it’s going to be communicated as “free-threading is done/committed” (just like the initial PEP acceptance was), so it won’t hurt to be unreasonably clear about exactly what’s being committed to.

2 Likes