Expand description
Pywaker provides a GIL-free way to wake up Python event loops from Rust. This is accomplished by writing a single byte to a “self pipe” for every wake up. The corresponding read-side FD is added to the Python-side event loop.
The approach does not add overhead in uncontended scenarios:
| Approach | Mean | Notes |
|----------------------|--------|---------------------------------|
| FD-based | ~48 µs | No GIL acquisition on Rust side |
| call_soon_threadsafe | ~56 µs | Acquires GIL on Rust side |
| Pure Python | ~44 µs | Baseline for comparison |§Implementation notes
event creates a pipe(2), and wakeup events are implemented by writing a single
byte into the pipe. The Python (read side) event registers the read fd into its
asyncio event loop. Thus the pipe acts as a notification queue. When the fd becomes
readable, the python event drains the pipe and then sets an asyncio.Event to notify
any waiters. [pipe] supplies the same pipe to a reader that is not an event loop,
such as a sync actor’s inbox, which waits on the read fd with poll.
Each read side has a single reader thread, and is thus free of race conditions: an event’s reads all occur within its asyncio event loop, which processes events sequentially on one thread, and a sync actor’s inbox is read only by its driver.
Structs§
- PyEvent
- An event that is awoken by a
Waker. - Waker
- Write side of a non-blocking self-pipe used to notify its receiver.
Functions§
- event
- Create a new event, returning the (Rust only)
Waker, and a PythonPyEvent, intended for passing to Python code. - register_
python_ bindings