Skip to main content

Module pywaker

Module pywaker 

Source
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         |

(Full benchmarks).

§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 Python PyEvent, intended for passing to Python code.
register_python_bindings