Skip to content

gh-145342: asyncio: Add guest mode for running inside external event loops#145343

Open
congzhangzh wants to merge 2 commits intopython:mainfrom
congzhangzh:add_asyncio_guest_mode
Open

gh-145342: asyncio: Add guest mode for running inside external event loops#145343
congzhangzh wants to merge 2 commits intopython:mainfrom
congzhangzh:add_asyncio_guest_mode

Conversation

@congzhangzh
Copy link

@congzhangzh congzhangzh commented Feb 28, 2026

Summary

Add asyncio.start_guest_run() which allows asyncio to run cooperatively
inside a host event loop (e.g. Tkinter, Qt, GTK). The host loop stays in
control of the main thread while asyncio I/O polling runs in a background
daemon thread.

Motivation

GUI applications with a native main loop (Tkinter, Qt, GTK) cannot use
asyncio.run() without blocking or replacing the host loop. Guest mode
enables incremental migration of GUI apps to async/await without replacing
the host event loop.

Implementation

  • Add Lib/asyncio/guest.py with start_guest_run().
  • Add three public methods to BaseEventLooppoll_events(),
    process_events(), and process_ready() — that decompose _run_once()
    into independently callable steps (zero behavior change for existing code).
  • Refactor _run_once() to delegate to the three new methods.
  • Add comprehensive tests in Lib/test/test_asyncio/test_guest.py using a
    mock host loop (no GUI dependency, 12 test methods).
  • Add a Tkinter demo in Doc/includes/asyncio_guest_tkinter.py.
  • Add RST reference documentation in Doc/library/asyncio-guest.rst.
  • Add NEWS entry.

Prior Art

Inspired by Trio's start_guest_run()
and the asyncio-guest proof-of-concept.

Testing

python -m pytest Lib/test/test_asyncio/test_guest.py -v

All 12 tests pass. The mock host loop tests cover: simple return, None return,
arguments, exceptions, cancellation from host, asyncio.sleep(), task creation,
asyncio.gather(), call_later, and call_soon_threadsafe.


📚 Documentation preview 📚: https://cpython-previews--145343.org.readthedocs.build/

…event loops

Add asyncio.start_guest_run() which allows asyncio to run cooperatively
inside a host event loop (e.g. Tkinter, Qt, GTK).  The host loop stays in
control of the main thread while asyncio I/O polling runs in a background
daemon thread.

Implementation:

- Add three public methods to BaseEventLoop -- poll_events(),
  process_events(), and process_ready() -- that decompose _run_once()
  into independently callable steps.
- Refactor _run_once() to delegate to these three methods (zero behaviour
  change for existing code).
- Add Lib/asyncio/guest.py with start_guest_run().
- Add comprehensive tests using a mock host loop (no GUI dependency).
- Add a Tkinter demo in Doc/includes/.

Inspired by Trio start_guest_run() and the asyncio-guest project.
@python-cla-bot
Copy link

python-cla-bot bot commented Feb 28, 2026

All commit authors signed the Contributor License Agreement.

CLA signed

@congzhangzh
Copy link
Author

@gvanrossum Hi Guido, I try to add guest mode to asyncio now, as I found that if I do not do it now, I will never have time to do it:)

Copy link
Contributor

@asvetlov asvetlov left a comment

Choose a reason for hiding this comment

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

How does the proposed approach work with the Windows proactor event loop?
Does the thread boundary crossing function well with IOCP ports?

_process_on_host([])

threading.Thread(
target=_backend, daemon=True, name='asyncio-guest-io'
Copy link
Contributor

Choose a reason for hiding this comment

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

A deamon thread smells like a red herring

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.

2 participants