How does the async runtime work internally in Rust (Waker, Poll, Executor)?
Answer
Rust's async system is built on the Future trait: fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>. Poll is either Ready(value) (the future is done) or Pending (not done yet). When a future returns Pending, it is responsible for ensuring the Waker (obtained from cx.waker()) will be called when the future is ready to make progress — typically by registering it with an I/O event loop (like epoll/kqueue). An Executor (the runtime, e.g., Tokio) maintains a queue of tasks. It polls a task; if it returns Pending, the executor parks it and moves on. When the Waker is invoked (by an I/O event), it re-queues the task for polling. This cooperative scheduling allows thousands of tasks to run efficiently on a small thread pool, with no overhead per idle task.
Previous
What are Pin<T> and Unpin in Rust async programming?
Next
What are the rules for writing correct unsafe Rust?
More Rust Questions
View all →- Advanced What are zero-cost abstractions and monomorphization in Rust?
- Advanced What are Pin<T> and Unpin in Rust async programming?
- Advanced What are the rules for writing correct unsafe Rust?
- Advanced How does Rust FFI (Foreign Function Interface) work with C?
- Advanced What is procedural macro metaprogramming with syn, quote, and proc_macro2?