Skip to content

[mypyc] Create function wrappers of nested coroutines lazily - #22048

Merged
JukkaL merged 4 commits into
masterfrom
mypyc-lazy-coroutine-wrapper
Sep 25, 2026
Merged

JukkaL merged 4 commits into
masterfrom
mypyc-lazy-coroutine-wrapper

Conversation

@JukkaL

@JukkaL JukkaL commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Each nested async def instance used to get it's own freshly allocated
function wrapper object, which is only needed relatively rarely for
introspection (e.g. __name__). This was slow to construct. Now we
construct this lazily. On free-threaded builds we need to deal with
other threads racing as well.

Top-level coroutines and methods are unaffected. Their wrappers were
already created once at import time.

Microbenchmark results (Python 3.14, 1M iterations):

  • create a nested coroutine closure: 197 ns -> 16 ns
  • create it and run the coroutine: 713 ns -> 526 ns

Each instance of a nested async def's callable class used to get its own
CPyFunction wrapper at instantiation. Creating it allocates a method def,
a code object, a name string and the function object, which made defining
a nested async def several times slower than calling it. The wrapper is
only used for introspection (__name__, __code__, __defaults__, etc.), so
create it on first access in the property getters and setters instead.

Microbenchmark (separate=True, Python 3.14, arm64 macOS; ns per call of
an outer coroutine that defines and awaits a nested async def):

  before  259.6
  after    69.6

In production profiles of a large async service, CPyFunction_New and
the wrapper's dealloc were ~0.16% of CPU.
Creating the wrapper may run arbitrary code (e.g. via GC) that could have
initialized the attribute already, so only store it if still NULL.
@JukkaL
JukkaL merged commit 5a52c4f into master Sep 25, 2026
18 checks passed
@JukkaL
JukkaL deleted the mypyc-lazy-coroutine-wrapper branch September 25, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants