Asynchronous programming usually aim to make it easier to reason about asynchronous operations. For example, by avoiding explicitly working with threads – the asynchronous library handles that itself– you can avoid complexity while avoiding the overhead of unnecessary thread spawning. In Rust, these constructs are ‘tasks.’ When you run a task, instead of blocking, it returns control to the executor thread. The task runs until it would block, then returns Async::Pending
. You also provide it a Waker
so that it can wake itself up again.
An executor works by running each of the tasks until they block, and then park
ing. A Waker
contains a link back to the executor and inserts the task in the executor’s ready set before unpark
ing it.
Futures are tasks that can be chained. They must implement a type Item that is the result of the computation, a type Error, and a poll method that returns Async::WillWake
or Async::Ready(data: Item)
.
Futures are designed to be state machines: eg, one that alterates between the states Reading
and Writing
, returning Async::NotReady
when it can’t proceed.