GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-150865: Add `PyUnstable_Immortalize` by ZeroIntensity · Pull Request #160138 · python/cpython

Conversation

@ZeroIntensity

@ZeroIntensity ZeroIntensity commented Oct 21, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Largely based on my old implementation for 3.14.

  • Issue: Relax PyUnstable_SetImmortal to objects allocated in that thread? #150865

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
ZeroIntensity added 6 commits October 21, 2026 16:47
@ZeroIntensity
I think this works?
4ac1f78
@ZeroIntensity
Simplify test cases.
3dce324
@ZeroIntensity
Disgusting hacks.
1a63e2a
@ZeroIntensity
Improve tests.
973d3ff
@ZeroIntensity
Don't use the traversal hack.
87d0c9a
@ZeroIntensity
Clean things up.
775cc1d
@ZeroIntensity
ZeroIntensity requested a review from ngoldbaum October 21, 2026 22:48
@ZeroIntensity ZeroIntensity added the sprint label Oct 21, 2026
@ZeroIntensity
ZeroIntensity requested review from AA-Turner, markshannon and methane as code owners October 21, 2026 22:48
@github-project-automation github-project-automation Bot added this to Sprint Oct 21, 2026
@github-project-automation github-project-automation Bot moved this to Todo in Sprint Oct 21, 2026
@bedevere-app bedevere-app Bot added the type-feature A feature request or enhancement label Oct 21, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Oct 21, 2026
Relax PyUnstable_SetImmortal to objects allocated in that thread? #150865
Open
@bedevere-app bedevere-app Bot added the awaiting core review label Oct 21, 2026
@ZeroIntensity
Update whatsnew.
3f51444
@read-the-docs-community

read-the-docs-community Bot commented Oct 21, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #35331167 | 📁 Comparing a41538d against main (aed4ad8)

  🔍 Preview build  

11 files changed · ± 11 modified

± Modified

  • license.html
  • c-api/object.html
  • library/argparse.html
  • library/binascii.html
  • library/curses.html
  • library/datetime.html
  • library/email.compat32-message.html
  • library/inspect.html
  • library/quopri.html
  • whatsnew/3.16.html
  • and 1 more...
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

ZeroIntensity added 2 commits October 21, 2026 19:23
@ZeroIntensity
Skip test under TSan.
1592d55
It's really slow under TSan so it times out.
@ZeroIntensity
Improve docs.
a41538d
@prathamhole14

prathamhole14 commented Oct 23, 2026

Copy link
Copy Markdown

Hi @ZeroIntensity thank you for the PR.

Immortal types are fixing the free-threaded slowdown for both PRs numpy/numpy/pull/32853 and numpy/numpy/pull/32552 about as well as the tp_free trick.

Benchmarks:

numpy/numpy/pull/32853 types (flagsobj, _array_converter), free-threaded, million calls/s**

Workload Threads static main (mortal) tp_free immortal
a.flags 1 13.9 10.6 9.8 10.3
a.flags 2 27.4 12.4 19.3 19.9
a.flags 4 54.4 9.1 37.8 39.7
a.flags 8 79.1 16.2 54.5 47.3
a.flags.writeable 8 51.5 16.6 37.9 39.5
np.require(a, ['A','W']) 8 4.38 3.78 3.77 4.10
np.broadcast_arrays(a, b) 8 0.60 0.54 0.61 0.61
a.shape (control) 8 64.2 60.5 67.5 63.7

linspace, unique and delete show no difference beyond noise in any build.

numpy/numpy/pull/32552 types (neighborhood iterator, MapIter), free-threaded, million calls/s**

Workload Threads static (main) mortal (your branch now) tp_free (as pushed) immortal
neighborhood iter 1 16.4 14.9 15.2 14.3
neighborhood iter 2 30.2 11.3 30.0 27.6
neighborhood iter 4 59.8 26.8 59.3 55.5
neighborhood iter 8 79.4 35.5 72.2 72.2
a[idx] (MapIter) 8 17.8 17.3 18.3 18.6

GIL build, one thread, ns per call (lower is better)

Workload static mortal tp_free immortal
a.flags 65.7 80.9 87.6 80.2
a.flags.writeable 93.3 105.8 113.6 106.2
neighborhood iter 75.9 76.5 84.1 77.5

import numpy takes the same time in every build (about 58 ms free-threaded, 52 ms GIL).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@prathamhole14 prathamhole14 mentioned this pull request Oct 24, 2026
ENH: Convert four self-contained multiarray types to heap types numpy/numpy#32552
Open
@ngoldbaum

ngoldbaum commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

@ZeroIntensity wasn't there another approach you were thinking about for this?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Oct 29, 2026

Copy link
Copy Markdown
Member Author

Per our discussion during the sprint, I think we reached a consensus that NumPy can use static types for things it would otherwise immortalize, right? As far as I can tell, it should be possible to share third-party static types across interpreters; the only requirement for subinterpreters is to use multi-phase initialization, which doesn't disallow static types. (If you find bugs with that, we should fix those!)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ngoldbaum

ngoldbaum commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

@prathamhole14 @mattip does that work for you two?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mattip

mattip commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

As far as I know, static types are incompatible with the limited API. If CPython wishes to allow c-extension authors to support subinterpreters, free-threading, and the limited API in a performant way, I think we need to be able to declare heap types immutable and immortal.

bschoenmaeckers and prathamhole14 reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Oct 30, 2026

Copy link
Copy Markdown
Member Author

The limited API already has performance problems (all the Py_INCREF calls can't be inlined, for example), which is why you should distribute per-version wheels anyway. Could NumPy use heap types when compiling for the limited API, and then use static types otherwise?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mattip

mattip commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

The Py_INCREF tax when using the limited API is indeed real and measurable, but fixed per call, with no thread contention. Being able to mark types as immortal solves problems of thread contention that go beyond the Py_INCREF tax, and allow recouping much of the performance impact when using multiple threads. Did the discussion at the sprint touch on the data @prathamhole14 showed above that shows how immortal objects scale with threads in the free threading (default) build? I find it a bit confusing that CPython would prefer a crippled limited API rather than showcasing it as the preferred alternative.

prathamhole14 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mattip

mattip commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

you should distribute per-version wheels anyway

Is this the general consensus?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ngoldbaum

ngoldbaum commented Nov 3, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

I think it'd be useful for NumPy to be able to optionally distribute limited API wheels on new platforms where we don't necessarily want to incur the cost of building several version-specific wheels.

Long-term, I think it would be great for NumPy to be able to migrate to using the limited API. But also NumPy is just about the hardest package to do this for because of the NumPy C API. I'm not at all surprised to find there are significant issues that might require several iterations to get right, allowing us to migrate without incurring large trade-offs.

prathamhole14 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

Is this the general consensus?

I'm not sure it's written down, but I think that's been the understanding whenever I've talked to people about this.

But now that I think about it, this wouldn't help for limited API builds anyway, because it won't be in the limited API. (We don't want to tie ourselves to immortality forever, so unfortunately there's a very slim chance that anything like this will make it into the limited API.)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@prathamhole14

prathamhole14 commented Nov 4, 2026

Copy link
Copy Markdown

As far as I can tell, it should be possible to share third-party static types across interpreters; the only requirement for subinterpreters is to use multi-phase initialization, which doesn't disallow static types. (If you find bugs with that, we should fix those!)

Although CPython only requires multi-phase init and nothing checks for static types but for the kind of subinterpreter concurrent.interpreters creates (each with its own GIL) static types are not safe on normal GIL builds.

I tried this with a small extension (multi-phase init, declaring Py_MOD_PER_INTERPRETER_GIL_SUPPORTED).
With no threads at all the subclassing a static type in the main interpreter and then in a subinterpreter crashes the process (double free or corruption on 3.14.6, free(): invalid pointer on 3.15.0rc2) every time (the same type as a heap type works totally fine).

I asked AI to investigate: CPython keeps one __dict__ and __mro__ and subclass list for a third-party static type, shared by all interpreters. CPython's own static types get a separate copy per interpreter (gh-94673) but extensions can't use that.

For NumPy this matters because import numpy itself subclasses ndarray.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

I asked AI to investigate: CPython keeps one dict and mro and subclass list for a third-party static type, shared by all interpreters. CPython's own static types get a separate copy per interpreter (#94673) but extensions can't use that.

Ok, I think we should fix that. I was under the impression that was what we already did for user-defined static types, but I guess not.

prathamhole14 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ngoldbaum ngoldbaum Awaiting requested review from ngoldbaum
@methane methane Awaiting requested review from methane methane is a code owner
@markshannon markshannon Awaiting requested review from markshannon markshannon is a code owner
@AA-Turner AA-Turner Awaiting requested review from AA-Turner AA-Turner is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

awaiting core review sprint type-feature A feature request or enhancement

Projects

Sprint
Status: Todo

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@ZeroIntensity @prathamhole14 @ngoldbaum @mattip
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.