Skip to content

CONCEPT Cited by 1 source

Async Rust Future

Definition

A Future in async Rust (std::future::Future) is a lazy state machine representing the eventual value of an asynchronous computation. Futures expose one operation — poll(&mut self, cx: &mut Context<'_>) -> Poll<T> — which an executor (e.g. Tokio) calls to advance the state machine. poll returns either Poll::Pending (not ready, will wake when it is) or Poll::Ready(T) (done, value here).

The laziness is crucial: Futures do not run on construction. Without an executor calling poll, nothing happens. This is what lets Rust compose Futures into deeply nested state machines at zero runtime allocation cost — and why the executor / event-loop layer (Tokio, async-std, smol) is the load-bearing integration point.

Ordinary Future vs streaming Future

"An ordinary Future is a one-shot value. Once it's Ready, it can't be polled anymore." (Source: sources/2025-02-26-flyio-taming-a-voracious-rust-proxy.)

For network I/O that isn't what you want — data arrives as a stream and you want to consume it incrementally. Async Rust addresses this with AsyncRead / AsyncWrite, which build on top of Futures but have a different contract: poll_read can return Ready every time there's data ready, so the caller keeps polling until it stops being Ready.

This split — one-shot Futures vs streaming AsyncRead — is exactly where the two async-Rust footguns live (see concepts/spurious-wakeup-busy-loop).

Integration with the executor

When an executor calls poll, it passes a Context containing a Waker. The Future clones the Waker and hands it to whatever is blocking it (a socket, a timer, an inner Future). When that thing progresses, it wakes the Waker, which tells the executor to re-poll this Future.

Skipping or accidentally double-firing the Waker breaks the abstraction — the executor either never re-polls (deadlock) or re-polls in a tight loop (busy-poll).

Seen in

Last updated · 200 distilled / 1,178 read