Skip to content

Conversation

@deadlovelll
Copy link

@deadlovelll deadlovelll commented Nov 4, 2025

This PR adds a high-level asynchronous API asyncio.run_in_subinterpreter for running Python functions
in subinterpreters. It uses InterpreterPoolExecutor internally and chooses the number of subinterpreters
based on the CPU count.

Motivation:

  • Enables CPU-bound tasks to run in parallel without being limited by the GIL.
  • Provides a lighter alternative to ProcessPoolExecutor.
  • Offers asyncio-friendly syntax.

Example usage:

import asyncio
from asyncio import run_in_subinterpreter

def cpu_task(x):
    return x * x

async def main():
    result = await run_in_subinterpreter(cpu_task, 10)
    # or
    result = await asyncio.run_in_subinterpreter(cpu_task, 10)
    print(result)

asyncio.run(main())

Tests:

  • Added unit tests for return values, argument passing, exception propagation, parallel calls,
    and complex objects.

@python-cla-bot
Copy link

python-cla-bot bot commented Nov 4, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be skipped when the implementation doesn't support subinterpreters. You probably just want something like:

try:
    from asyncio import run_in_subinterpreter
except ImportError:
    raise unittest.SkipTest("subinterpreters not supported")

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, fixed

from .timeouts import *
from .threads import *
from .transports import *
from .subinterpreters import *
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to handle other implementations here. If this fails with an ImportError, it shouldn't prevent the whole module from being imported.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, fixed

worker_count: int | None = None
if n:
worker_count = max(1, n // 2)
with InterpreterPoolExecutor(max_workers=worker_count) as pool:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we only want one worker?

worker_count = max(1, n // 2)
with InterpreterPoolExecutor(max_workers=worker_count) as pool:
future = pool.submit(func, *args, **kwargs)
return future.result() No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, this never yields to the event loop, so it doesn't let anything else run while the subinterpreter executes (defeating the point of this API entirely).

I think you want to use something like loop.run_in_executor or asyncio.to_thread. The event loop needs to yield while executing the synchronous code in another interpreter. Here's a simple POC:

import asyncio
from concurrent import interpreters


async def run_in_subinterpreter(func):
    interp = interpreters.create()
    try:
        await asyncio.to_thread(interp.call, func)
    finally:
        interp.close()

def compute_synchronous_stuff():
    for n in range(10000):
        n ** n

async def work():
    print("doing async I/O")
    await asyncio.sleep(1)
    print("done")

async def main():
    task = asyncio.create_task(work())
    print("doing sync I/O")
    # The task can execute while this is running
    await run_in_subinterpreter(compute_synchronous_stuff)
    print("done")
    await task


asyncio.run(main())

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, it was like a blueprint for the issue i created, also changed this to non-blocking implementation

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Nov 4, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@picnixz picnixz closed this Nov 7, 2025
@picnixz
Copy link
Member

picnixz commented Nov 7, 2025

Closing as it was deemed unnecessary

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants