Move draft from wg-net

This commit is contained in:
Aaron Turon 2018-12-12 18:18:22 -05:00
parent 29c28ccb7e
commit d598899e95
15 changed files with 1481 additions and 1 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 The Rust Programming Language
Copyright (c) 2018 Aaron Turon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

34
src/TOC.md Normal file
View File

@ -0,0 +1,34 @@
# Table of Contents
- [Getting Started](getting_started/chapter.md)
- [What This Book Covers](getting_started/chapter.md#what-this-book-covers)
- [Why Async?](getting_started/why_async.md)
- [The State of Asynchronous Rust](getting_started/state_of_async_rust.md)
- [`async`/`await!` Primer](getting_started/async_await_primer.md)
- [Applied: HTTP Server](getting_started/http_server_example.md)
- [Under the Hood: Executing `Future`s and Tasks](execution/chapter.md)
- [The `Future` Trait](execution/future.md)
- [Task Wakeups with `LocalWaker` and `Waker`](execution/wakeups.md)
- [Applied: Build a Timer](execution/wakeups.md)
- [Applied: Build an Executor](execution/executor.md)
- [Executors and System IO](execution/io.md)
- [`async`/`await`]()
- [What and Why]()
- [`async` Blocks, Closures, and Functions]()
- [Applied: XXX]()
- [Pinning](pinning/chapter.md)
- [Practical Usage](pinning/chapter.md#how-to-use-pinning)
- [Streams](streams/chapter.md)
- [Patterns: Iteration and Concurrency]()
- [Executing Multiple Futures at a Time]()
- [`select!` and `join!`]()
- [Spawning]()
- [Cancellation and Timeouts]()
- [`FuturesUnordered`]()
- [I/O]()
- [`AsyncRead` and `AsyncWrite`]()
- [Asynchronous Design Patterns: Solutions and Suggestions]()
- [Modeling Servers and the Request/Response Pattern]()
- [Managing Shared State]()
- [The Ecosystem: Tokio and More]()
- Lots, lots more?...

154
src/async_await/chapter.md Normal file
View File

@ -0,0 +1,154 @@
# `async`/`await!`
In [the first chapter], we took a brief look at `async`/`await!` and used
it to build a simple server. This chapter will discuss `async`/`await!` in
greater detail, explaining how it works and how `async` code differs from
traditional Rust programs.
`async`/`await!` are special pieces of Rust syntax that make it possible to
yield control of the current thread rather than blocking, allowing other
code to make progress while waiting on an operation to complete.
There are three main ways to use `async`: `async fn`, `async` blocks, and
`async` closures. Each returns a value that implements the `Future` trait:
```rust
// `foo()` returns a type that implements `Future<Output = u8>`.
// `await!(foo())` will result in a value of type `u8`.
async fn foo() -> u8 { 5 }
fn bar() -> impl Future<Output = u8> {
// This `async` block results in a type that implements
// `Future<Output = u8>`.
async {
let x: u8 = await!(foo());
x + 5
}
}
fn baz() -> impl Future<Output = u8> {
// This `async` closure, when called, returns a type that
// implements `Future<Output = u8>`
let closure = async |x: u8| {
await!(bar()) + x
};
closure(5)
}
```
As we saw in the first chapter, `async` bodies and other futures are lazy:
they do nothing until they are run. The most common way to run a `Future`
is to `await!` it. When `await!` is called on a `Future`, it will attempt
to run it to completion. If the `Future` is blocked, it will yield control
of the current thread. When more progress can be made, the `Future` will be picked
up by the executor and will resume running, allowing the `await!` to resolve.
## `async` Lifetimes
Unlike traditional functions, `async fn`s which take references or other
non-`'static` arguments return a `Future` which is bounded by the lifetime of
the arguments:
```rust
// This function:
async fn foo(x: &u8) -> u8 { *x }
// Is equivalent ot this function:
fn foo<'a>(x: &'a u8) -> impl Future<Output = ()> + 'a {
async { *x }
}
```
This means that the future returned from an `async fn` must be `await!`ed
while its non-`'static` arguments are still valid. In the common
case of `await!`ing the future immediately after calling the function
(like `await!(foo(&x))`) this is not an issue. However, if storing the future
or sending it over to another task or thread, this may be an issue.
One common workaround for turning an `async fn` with references-as-arguments
into a `'static` future is to bundle the arguments with the call to the
`async fn` inside an `async` block:
```rust
async fn foo(x: &u8) -> u8 { *x }
fn bad() -> impl Future<Output = ()> {
let x = 5;
foo(&x) // ERROR: `x` does not live long enough
}
fn good() -> impl Future<Output = ()> {
async {
let x = 5;
await!(foo(&x))
}
}
```
By moving the argument into the `async` block, we extend its lifetime to match
that of the `Future` returned from the call to `foo`.
## `async move`
`async` blocks and closures allow the `move` keyword, much like normal
closures. An `async move` block will take ownership of the variables it
references, allowing it to outlive the current scope, but giving up the ability
to share those variables with other code:
```rust
/// `async` block:
///
/// Multiple different `async` blocks can access the same local variable
/// so long as they're executed within the variable's scope.
async fn foo() {
let my_string = "foo".to_string();
let future_one = async {
...
println!("{}", my_string);
};
let future_two = async {
...
println!("{}", my_string);
};
// Run both futures to completion, printing "foo" twice
let ((), ()) = join!(future_one, future_two);
}
/// `async move` block:
///
/// Only one `async` block can access captured variables, since they are
/// moved into the `Future` generated by the `async` block. However,
/// this allows the `Future` to outlive the original scope of the variable:
fn foo() -> impl Future<Output = ()> {
let my_string = "foo".to_string();
async move {
...
println!("{}", my_string);
}
}
```
## `await!`ing on a Multithreaded Executor
Note that, when using a multithreaded `Future` executor, a `Future` may move
between threads, so any variables used in `async` bodies must be able to travel
between threads, as any `await!` can potentially result in a switch to a new
thread.
This means that it is not safe to use `Rc`, `&RefCell` or any other types
that don't implement the `Send` trait, including references to types that don't
implement the `Sync` trait.
(Caveat: it is possible to use these types so long as they aren't in scope
during a call to `await!`.)
Similarly, it isn't a good idea to hold a traditional non-futures-aware lock
across an `await!`, as it can cause the threadpool to lock up: one task could
take out a lock, `await!` and yield to the executor, allowing another task to
attempt to take the lock and cause a deadlock. To avoid this, use the `Mutex`
in `futures::lock` rather than the one from `std::sync`.
[the first chapter]: TODO ../getting_started/async_await_primer.md

13
src/execution/chapter.md Normal file
View File

@ -0,0 +1,13 @@
# Under the Hood: Executing `Future`s and Tasks
In this section, we'll cover the underlying structure of how `Future`s and
asynchronous tasks are scheduled. If you're only interested in learning
how to write higher-level code that uses existing `Future` types and aren't
interested in the details of how `Future` types work, you can skip ahead to
the `async`/`await` chapter. However, several of the topics discussed in this
chapter are useful for understanding how `async`/`await` code works,
understanding the runtime and performance properties of `async`/`await` code,
and building new asynchronous primitives. If you decide to skip this section
now, you may want to bookmark it to revisit in the future.
Now, with that out of the, way, let's talk about the `Future` trait.

183
src/execution/executor.md Normal file
View File

@ -0,0 +1,183 @@
# Applied: Build an Executor
`Future`s are lazy and must be actively driven to completion in order to do
anything. A common way to drive a future to completion is to `await!` it inside
an `async` function, but that just pushes the problem one level up: who will
run the futures returned from the top-level `async` functions? The answer is
that we need a `Future` executor.
`Future` executors take a set of top-level `Future`s and run them to completion
by calling `poll` whenever the `Future` can make progress. Typically, an
executor will `poll` a future once to start off. When `Future`s indicate that
they are ready to make progress by calling `wake()`, they are placed back
onto a queue and `poll` is called again, repeating until the `Future` has
completed.
In this section, we'll write our own simple executor capable of running a large
number of top-level futures to completion concurrently.
For this one, we're going to have to include the `futures` crate in order to
get the `FutureObj` type, which is a dynamically-dispatched `Future`, similar
to `Box<dyn Future<Output = T>>`. `Cargo.toml` should look something like this:
```toml
[package]
name = "xyz"
version = "0.1.0"
authors = ["XYZ Author"]
edition = "2018"
[dependencies]
futures-preview = "0.3.0-alpha.9"
```
Next, we need the following imports at the top of `src/main.rs`:
```rust
#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
use {
futures::future::FutureObj,
std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
sync::mpsc::{sync_channel, SyncSender, Receiver},
task::{
local_waker_from_nonlocal,
Poll, Wake,
},
},
};
```
Our executor will work by sending tasks to run over a channel. The executor
will pull events off of the channel and run them. When a task is ready to
do more work (is awoken), it can schedule itself to be polled again by
putting itself back onto the channel.
In this design, the executor itself just needs the receiving end of the task
channel. The user will get a sending end so that they can spawn new futures.
Tasks themselves are just futures that can reschedule themselves, so we'll
store them as a future paired with a sender that the task can use to requeue
itself.
```rust
/// Task executor that receives tasks off of a channel and runs them.
struct Executor {
ready_queue: Receiver<Arc<Task>>,
}
/// `Spawner` spawns new futures onto the task channel.
#[derive(Clone)]
struct Spawner {
task_sender: SyncSender<Arc<Task>>,
}
/// A future that can reschedule itself to be polled using a channel.
struct Task {
// In-progress future that should be pushed to completion
//
// The `Mutex` is not necessary for correctness, since we only have
// one thread executing tasks at once. However, `rustc` isn't smart
// enough to know that `future` is only mutated from one thread,
// so we use it in order to provide safety. A production executor would
// not need this, and could use `UnsafeCell` instead.
future: Mutex<Option<FutureObj<'static, ()>>>,
// Handle to spawn tasks onto the task queue
task_sender: SyncSender<Arc<Task>>,
}
fn new_executor_and_spawner() -> (Executor, Spawner) {
// Maximum number of tasks to allow queueing in the channel at once.
// This is just to make `sync_channel` happy, and wouldn't be present in
// a real executor.
const MAX_QUEUED_TASKS: usize = 10_000;
let (task_sender, ready_queue) = sync_channel(MAX_QUEUED_TASKS);
(Executor { ready_queue }, Spawner { task_sender})
}
```
Let's also add a method to spawner to make it easy to spawn new futures.
This method will take a future type, box it and put it in a FutureObj,
and create a new `Arc<Task>` with it inside which can be enqueued onto the
executor.
```rust
impl Spawner {
fn spawn(&self, future: impl Future<Output = ()> + 'static + Send) {
let future_obj = FutureObj::new(Box::new(future));
let task = Arc::new(Task {
future: Mutex::new(Some(future_obj)),
task_sender: self.task_sender.clone(),
});
self.task_sender.send(task).expect("too many tasks queued");
}
}
```
In order poll futures, we'll also need to create a `LocalWaker` to provide to
poll. As discussed in the [task wakeups section], `LocalWaker`s are responsible
for scheduling a task to be polled again once `wake` is called. Remember that
`LocalWaker`s tell the executor exactly which task has become ready, allowing
them to poll just the futures that are ready to make progress. The easiest way
to create a new `LocalWaker` is by implementing the `Wake` trait and then using
the `local_waker_from_nonlocal` or `local_waker` functions to turn a `Arc<T: Wake>`
into a `LocalWaker`. Let's implement `Wake` for our tasks to allow them to be
turned into `LocalWaker`s and awoken:
```rust
impl Wake for Task {
fn wake(arc_self: &Arc<Self>) {
// Implement `wake` by sending this task back onto the task channel
// so that it will be polled again by the executor.
let cloned = arc_self.clone();
arc_self.task_sender.send(cloned).expect("too many tasks queued");
}
}
```
When a `LocalWaker` is created from an `Arc<Task>`, calling `wake()` on it will
cause a copy of the `Arc` to be sent onto the task channel. Our executor then
needs to pick up the task and poll it. Let's implement that:
```rust
impl Executor {
fn run(&self) {
while let Ok(task) = self.ready_queue.recv() {
let mut future_slot = task.future.lock().unwrap();
// Take the future, and if it has not yet completed (is still Some),
// poll it in an attempt to complete it.
if let Some(mut future) = future_slot.take() {
// Create a `LocalWaker` from the task itself
let lw = local_waker_from_nonlocal(task.clone());
if let Poll::Pending = Pin::new(&mut future).poll(&lw) {
// We're not done processing the future, so put it
// back in its task to be run again in the future.
*future_slot = Some(future);
}
}
}
}
}
```
Congratulations! We now have a working futures executor. We can even use it
to run `async/await!` code and custom futures, such as the `TimerFuture` we
wrote earlier:
```rust
fn main() {
let (executor, spawner) = new_executor_and_spawner();
spawner.spawn(async {
println!("howdy!");
// Wait for our timer future to complete after two seconds.
await!(TimerFuture::new(Duration::new(2, 0)));
println!("done!");
});
executor.run();
}
```
[task wakeups section]: TODO

189
src/execution/future.md Normal file
View File

@ -0,0 +1,189 @@
# The `Future` Trait
The `Future` trait is at the center of asynchronous programming in Rust.
A `Future` is an asynchronous computation that can produce a value
(although that value may be empty, e.g. `()`). A *simplified* version of
the future trait might look something like this:
```rust
trait SimpleFuture {
type Output;
fn poll(&mut self, wake: fn()) -> Poll<Self::Output>;
}
enum Poll<T> {
Ready(T),
Pending,
}
```
Futures can be advanced by calling the `poll` function, which will drive the
future as far towards completion as possible. If the future completes, it
returns `Poll::Ready(result)`. If the future is not able to complete yet, it
returns `Poll::Pending` and arranges for the `wake()` function to be called
when the `Future` is ready to make more progress. When `wake()` is called, the
executor driving the `Future` will call `poll` again so that the `Future` can
make more progress.
Without `wake()`, the executor would have no way of knowing when a particular
future could make progress, and would have to be constantly polling every
future. With `wake()`, the executor knows exactly which futures are ready to
be `poll`ed.
For example, consider the case where we want to read from a socket that may
or may not have data available already. If there is data, we can read it
in and return `Poll::Ready(data)`, but if no data is ready, our future is
blocked and can no longer make progress. When no data is available, we
must register `wake` to be called when data becomes ready on the socket,
which will tell the executor that our future is ready to make progress.
A simple `SocketRead` future might look something like this:
```rust
struct SocketRead<'a> {
socket: &'a Socket,
}
impl SimpleFuture for SocketRead<'_> {
type Output = Vec<u8>;
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
if self.socket.has_data_to_read() {
// The socket has data-- read it into a buffer and return it.
Poll::Ready(self.socket.read_buf())
} else {
// The socket does not yet have data.
//
// Arrange for `wake` to be called once data is available.
// When data becomes available, `wake` will be called, and the
// user of this `Future` will know to call `poll` again and
// receive data.
self.socket.set_readable_callback(wake);
Poll::Pending
}
}
}
```
This model of `Future`s allows for composing together multiple asynchronous
operations without needing intermediate allocations. Running multiple futures
at once or chaining futures together can be implemented via allocation-free
state machines, like this:
```rust
/// A SimpleFuture that runs two other futures to completion concurrently.
///
/// Concurrency is achieved via the fact that calls to `poll` each future
/// may be interleaved, allowing each future to advance itself at its own pace.
struct Join2 {
// Each field may contain a future that should be run to completion.
// If the future has already completed, the field is set to `None`.
a: Option<FutureA>,
b: Option<FutureB>,
}
impl SimpleFuture for Join2 {
type Output = ();
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
// Attempt to complete future `a`.
let finished_a = match &mut self.a {
Some(a) => {
match a.poll(wake) {
Poll::Ready(()) => true,
Poll::Pending => false,
}
}
None => true,
};
if finished_a { self.a.take() }
// Attempt to complete future `b`.
let finished_b = match &mut self.b {
Some(b) => {
match b.poll(wake) {
Poll::Ready(()) => true,
Poll::Pending => false,
}
}
None => true,
};
if finished_b { self.b.take() }
if finished_a && finished_b {
// Both futures have completed-- we can return successfully
Poll::Ready(())
} else {
// One or both futures still have work to do, and will call
// `wake()` when progress can be made.
Poll::Pending
}
}
}
```
This shows how multiple futures can be run simultaneously without needing
separate allocations, allowing for more efficient asynchronous programs.
Similarly, multiple sequential futures can be run one after another, like this:
```rust
/// A SimpleFuture that runs two futures to completion, one after another.
//
// Note: for the purposes of this simple example, `AndThenFut` assumes both
// the first and second futures are available at creation-time. The real
// `AndThen` combinator allows creating the second future based on the output
// of the first future, like `get_breakfast.and_then(|food| eat(food))`.
enum AndThenFut {
first: Option<FutureA>,
second: FutureB,
}
impl SimpleFuture for AndThenFut {
type Output = ();
fn poll(&mut self, wake: fn()) -> Poll<Self::Output> {
if let Some(first) = &mut self.first {
match first.poll(wake) {
// We've completed the first future-- remove it and start on
// the second!
Poll::Ready(()) => self.first.take(),
// We couldn't yet complete the first future.
Poll::Pending => return Poll::Pending,
}
}
// Now that the first future is done, attempt to complete the second.
second.poll(wake)
}
}
```
These examples show how the `Future` trait can be used to express asynchronous
control flow without requiring multiple allocated objects and deeply nested
callbacks. With the basic control-flow out of the way, let's talk about the
real `Future` trait and how it is different.
```rust
trait Future {
type Output;
fn poll(
// note the change from `&mut self` to `Pin<&mut Self>`
self: Pin<&mut Self>,
lw: &LocalWaker, // note the change from `wake: fn()`
) -> Poll<Self::Output>;
}
```
The first change you'll notice is that our `self` type is no longer `&mut self`,
but has changed to `Pin<&mut Self>`. We'll talk more about pinning in [a later
section][pinning], but for now know that it allows us to create futures that
are immovable. Immovable objects can store pointers between their fields,
e.g. `struct MyFut { a: i32, ptr_to_a: *const i32 }`. This feature is necessary
in order to enable async/await.
Secondly, `wake: fn()` has changed to `LocalWaker`. In `SimpleFuture`, we used
a call to a function pointer (`fn()`) to tell the future executor that the
future in question should be polled. However, since `fn()` is zero-sized, it
can't store any data about *which* `Future` called `wake`.
In a real-world scenario, a complex application like a web server may have
thousands of different connections whose wakeups should all be
managed separately. This is where `LocalWaker` and its sibling type `Waker`
come in.
[pinning]: TODO

135
src/execution/io.md Normal file
View File

@ -0,0 +1,135 @@
# Executors and System IO
In the previous section on [The `Future` Trait], we discussed this example of
a future that performed an asynchronous read on a socket:
```rust
struct SocketRead<'a> {
socket: &'a Socket,
}
impl SimpleFuture for SocketRead<'_> {
type Output = Vec<u8>;
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> {
if self.socket.has_data_to_read() {
// The socket has data-- read it into a buffer and return it.
Poll::Ready(self.socket.read_buf())
} else {
// The socket does not yet have data.
//
// Arrange for `wake` to be called once data is available.
// When data becomes available, `wake` will be called, and the
// user of this `Future` will know to call `poll` again and
// receive data.
self.socket.set_readable_callback(lw);
Poll::Pending
}
}
}
```
This future will read available data on a socket, and if no data is available,
it will yield to the executor, requesting that its task be awoken when the
socket becomes readable again. However, it's not clear from this example how
the `Socket` type is implemented, and in particular it isn't obvious how the
`set_readable_callback` function works. How can we arrange for `lw.wake()`
to be called once the socket becomes readable? One option would be to have
a thread that continually checks whether `socket` is readable, calling
`wake()` when appropriate. However, this would be quite inefficient, requiring
a separate thread for each blocked IO future. This would greatly reduce the
efficiency of our async code.
In practice, this problem is solved through integration with an IO-aware
system blocking primitive, such as `epoll` on Linux, `kqueue` on FreeBSD and
Mac OS, IOCP on Windows, and `port`s on Fuchsia (all of which are exposed
through the cross-platform Rust crate [`mio`]). These primitives all allow
a thread to block on multiple asynchronous IO events, returning once one of
the events completes. In practice, these APIs usually look something like
this:
```rust
struct IoBlocker {
...
}
struct Event {
// An ID uniquely identifying the event that occurred and was listened for.
id: usize,
// A set of signals to wait for, or which occurred.
signals: Signals,
}
impl IoBlocker {
/// Create a new collection of asynchronous IO events to block on.
fn new() -> Self { ... }
/// Express an interest in a particular IO event.
fn add_io_event_interest(
&self,
/// The object on which the event will occur
io_object: &IoObject,
/// A set of signals that may appear on the `io_object` for
/// which an event should be triggered, paried with
/// an ID to give to events that result from this interest.
event: Event,
) { ... }
/// Block until one of the events occurs.
/// This will only trigget
fn block(&self) -> Event { ... }
}
let mut io_blocker = IoBlocker::new();
io_blocker.add_io_event_interest(
&socket_1,
Event { id: 1, signals: READABLE },
);
io_blocker.add_io_event_interest(
&socket_2,
Event { id: 2, signals: READABLE | WRITABLE },
);
let event = io_blocker.block();
// prints e.g. "Socket 1 is now READABLE" if socket one became readable.
println!("Socket {:?} is now {:?}", event.id, event.signals);
```
Futures executors can use these primitives to provide asynchronous IO objects
such as sockets that can configure callbacks to be run when a particular IO
event occurs. In the case of our `SocketRead` example above, the
`Socket::set_readable_callback` function might look like the following pseudocode:
```rust
impl Socket {
fn set_readable_callback(&self, lw: &LocalWaker) {
// `local_executor` is a reference to the local executor.
// this could be provided at creation of the socket, but in practice
// many executor implementations pass it down through thread local
// storage for convenience.
let local_executor = self.local_executor;
// Unique ID for this IO object.
let id = self.id;
// Store the local waker in the executor's map so that it can be called
// once the IO event arrives.
local_executor.event_map.insert(id, lw.clone());
local_executor.add_io_event_interest(
&self.socket_file_descriptor,
Event { id, signals: READABLE },
);
}
}
```
We can now have just one executor thread which can receive and dispatch any
IO event to the appropriate `LocalWaker`, which will wake up the corresponding
task, allowing the executor to drive more tasks to completion before returning
to check for more IO events (and the cycle continues...).
[The `Future` Trait]: TODO
[`mio`]: https://github.com/carllerche/mio

142
src/execution/wakeups.md Normal file
View File

@ -0,0 +1,142 @@
# Task Wakeups with `LocalWaker` and `Waker`
It's common that futures aren't able to complete the first time they are
`poll`ed. When this happens, the future needs to ensure that it is polled
again once it is ready to make more progress. This is done with the
`LocalWaker` and `Waker` types.
Each time a future is polled, it is polled as part of a "task". Tasks are
the top-level futures that have been submitted to an executor.
`LocalWaker` and `Waker` each provide a `wake()` method that can be used to
tell the executor that their associated task should be awoken. When `wake()` is
called, the executor knows that the task associated with the `Waker` is ready to
make progress, and its future should be polled again.
`LocalWaker` and `Waker` also implement `clone()` so that
they can be copied around and stored. The difference between the two is
thread-safety: `LocalWaker` is `!Send` and `!Sync`, and so cannot be used from
threads other than the one it was created from. This allows `LocalWaker`
implementations to perform special optimized behavior for the current thread.
`Waker`s, on the other hand, are `Send` and `Sync`, and so can be used across
multiple threads. A `LocalWaker` can be turned into a thread-safe `Waker` using
the `into_waker()` function. This function is free to call-- it doesn't
allocate at runtime or anything similar, but calling `wake()` on the resulting
`Waker` may be less performant than calling `wake()` on the original
`LocalWaker`.
Let's try implementing a simple timer future using `Waker` and `LocalWaker`.
## Applied: Build a Timer
For the sake of the example, we'll just spin up a new thread when the timer
is created, sleep for the required time, and then signal the timer future
when the time window has elapsed.
Here are the imports we'll need to get started:
```rust
#![feature(arbitrary_self_types, futures_api, pin)]
use std::{
future::Future,
pin::{Pin, Unpin},
sync::{Arc, Mutex},
task::{LocalWaker, Poll, Waker},
thread,
time::Duration,
};
```
Let's start by defining the future type itself. Our future needs a way for the
thread to communicate that the timer has elapsed and the future should complete.
We'll use a shared `Arc<Mutex<..>>` value to communicate between the thread and
the future.
```rust
struct TimerFuture {
shared_state: Arc<Mutex<SharedState>>,
}
/// Shared state between the future and the thread
struct SharedState {
/// Whether or not the sleep time has elapsed
completed: bool,
/// The waker for the task that `TimerFuture` is running on.
/// The thread can use this after setting `completed = true` to tell
/// `TimerFuture`'s task to wake up, see that `completed = true`, and
/// move forward.
waker: Option<Waker>,
}
// Pinning will be covered later-- for now, it's enough to understand that our
// `TimerFuture` type doesn't require it, so it is `Unpin`.
impl Unpin for TimerFuture {}
```
Now, let's actually write the `Future` implementation!
```rust
impl Future for TimerFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, lw: &LocalWaker)
-> Poll<Self::Output>
{
// Look at the shared state to see if the timer has already completed.
let mut shared_state = self.shared_state.lock().unwrap();
if shared_state.completed {
Poll::Ready(())
} else {
// Set waker so that the thread can wake up the current task
// when the timer has completed, ensuring that the future is polled
// again and sees that `completed = true`.
shared_state.waker = Some(lw.clone().into_waker());
Poll::Pending
}
}
}
```
Pretty simple, right? If the thread has set `shared_state.completed = true`,
we're done! Otherwise, we clone the `LocalWaker` for the current task,
convert it into a `Waker`, and pass it to `shared_state.waker` so that the
thread can wake the task back up.
Importantly, we have to update the `Waker` every time the future is polled
because the future may have moved to a different task with a different
`Waker`. This will happen when futures are passed around between tasks after
being polled.
Finally, we need the API to actually construct the timer and start the thread:
```rust
impl TimerFuture {
/// Create a new `TimerFuture` which will complete after the provided
/// timeout.
pub fn new(duration: Duration) -> Self {
let shared_state = Arc::new(Mutex::new(SharedState {
completed: false,
waker: None,
}));
// Spawn the new thread
let thread_shared_state = shared_state.clone();
thread::spawn(move || {
thread::sleep(duration);
let mut shared_state = thread_shared_state.lock().unwrap();
// Signal that the timer has completed and wake up the last
// task on which the future was polled, if one exists.
shared_state.completed = true;
if let Some(waker) = &shared_state.waker {
waker.wake();
}
});
TimerFuture { shared_state }
}
}
```
Woot! That's all we need to build a simple timer future. Now, if only we had
an executor to run the future on...

View File

@ -0,0 +1,103 @@
# `async`/`await!` Primer
`async`/`await!` is Rust's built-in tool for writing asynchronous functions
that look like synchronous code. `async` transforms a block of code into a
state machine that implements a trait called `Future`. Whereas calling a
blocking function in a synchronous method would block the whole thread,
blocked `Future`s will yield control of the thread, allowing other
`Future`s to run.
To create an asynchronous function, you can use the `async fn` syntax:
```rust
async fn do_something() { ... }
```
The value returned by `async fn` is a `Future` that needs to be run on
an executor in order for anything to happen:
```rust
// `block_on` blocks the current thread until the provided future has run to
// completion. Other executors provide more complex behavior, like scheudling
// multiple futures onto the same thread.
use futures::executor::block_on;
async fn hello_world() {
println!("hello, world!");
}
fn main() {
let future = hello_world(); // Nothing is printed
block_on(future); // `future` is run and "hello, world!" is printed
}
```
Inside an `async fn`, you can use `await!` to wait for the completion of
another type that implements the `Future` trait, such as the output of
another `async fn`. Unlike `block_on`, `await!` doesn't block the current
thread, but instead asynchronously waits for the future to complete, allowing
other tasks to run if the future is currently unable to make progress.
For example, imagine that we have three `async fn`: `learn_song`, `sing_song`,
and `dance`:
```rust
async fn learn_song() -> Song { ... }
async fn sing_song(song: Song) { ... }
async fn dance() { ... }
```
One way to do learn, sing, and dance would be to block on each of these
individually:
```rust
fn main() {
let song = block_on(learn_song());
block_on(sing_song(song));
block_on(dance);
}
```
However, we're not giving the best performance possible this way-- we're
only ever doing one thing at once! Clearly we have to learn the song before
we can sing it, but it's possible to dance at the same time as learning and
singing the song. To do this, we can create two separate `async fn` which
can be run concurrently:
```rust
async fn learn_and_sing() {
// Wait until the song has been learned before singing it.
// We use `await!` here rather than `block_on` to prevent blocking the
// thread, which makes it possible to `dance` at the same time.
let song = await!(learn_song());
await!(sing_song(song));
}
async fn async_main() {
let f1 = learn_and_sing();
let f2 = dance();
// `join!` is like `await!` but can wait for multiple futures concurrently.
// If we're temporarily blocked in the `learn_and_sing` future, the `dance`
// future will take over the current thread. If `dance` becomes blocked,
// `learn_and_sing` can take back over. If both futures are blocked, then
// `async_main` is blocked and will yield to the executor.
join!(f1, f2)
}
fn main() {
block_on(async_main());
}
```
In this example, learning the song must happen before singing the song, but
both learning and singing can happen at the same time as dancing. If we used
`block_on(learn_song())` rather than `await!(learn_song())` in `learn_and_sing`,
the thread wouldn't be able to do anything else while `learn_song` was running.
This would make it impossible to dance at the same time. By `await!`ing
the `learn_song` future, we allow other tasks to take over the current thread
if `learn_song` is blocked. This makes it possible to run multiple futures
to completion concurrently on the same thread.
Now that you've learned the basics of `async`/`await!`, let's try out an
example.

View File

@ -0,0 +1,25 @@
# Getting Started
Welcome to Asynchronous Programming in Rust! If you're looking to start writing
asynchronous Rust code, you've come to the right place. Whether you're building
a web server, a database, or an operating system, this book will show you
how to use Rust's asynchronous programming tools to get the most out of your
hardware.
## What This Book Covers
This book aims to be a comprehensive, up-to-date guide to using Rust's async
language features and libraries, appropriate for beginners and old hands alike.
- The early chapters provide an introduction to async programming in general,
and to Rust's particular take on it.
- The middle chapters discuss key utilities and control-flow tools you can use
when writing async code, and describe best-practices for structuring libraries
and applications to maximize performance and reusability.
- The last section of the book covers the broader async ecosystem, and provides
a number of examples of how to accomplish common tasks.
With that out of the way, let's explore the exciting world of Asynchronous
Programming in Rust!

View File

@ -0,0 +1,199 @@
# Applied: Simple HTTP Server
Let's use `async`/`await!` to build an echo server!
To start, run `rustup update nightly` to make sure you've got the latest and
greatest copy of Rust-- we're working with bleeding-edge features, so it's
essential to stay up-to-date. Once you've done that, run
`cargo +nightly new async-await-echo` to create a new project, and open up
the resulting `async-await-echo` folder.
Let's add some dependencies to the `Cargo.toml` file:
```toml
[dependencies]
# The latest version of the "futures" library, which has lots of utilities
# for writing async code. Enable the "tokio-compat" feature to include the
# functions for using futures 0.3 and async/await with the Tokio library.
futures-preview = { version = "0.3.0-alpha.9", features = ["tokio-compat"] }
# Hyper is an asynchronous HTTP library. We'll use it to power our HTTP
# server and to make HTTP requests.
hyper = "0.12.9"
# Tokio is a runtime for asynchronous I/O applications. Hyper uses
# it for the default server runtime. The `tokio` crate also provides an
# an `await!` macro similar to the one in `std`, but it supports `await!`ing
# both futures 0.1 futures (the kind used by Hyper and Tokio) and
# futures 0.3 futures (the kind produced by the new `async`/`await!` language
# feature).
tokio = { version = "0.1.11", features = ["async-await-preview"] }
```
Now that we've got our dependencies out of the way, let's start writing some
code. Open up `src/main.rs` and enable the following features at the top of
the file:
```rust
#![feature(async_await, await_macro, futures_api)]
```
- `async_await` adds support for the `async fn` syntax.
- `await_macro` adds support for the `await!` macro.
- `futures_api` adds support for the nightly `std::future` and `std::task`
modules which define the core `Future` trait and dependent types.
Additionally, we have some imports to add:
```rust
use {
hyper::{
// Miscellaneous types from Hyper for working with HTTP.
Body, Client, Request, Response, Server, Uri,
// This function turns a closure which returns a future into an
// implementation of the the Hyper `Service` trait, which is an
// asynchronous function from a generic `Request` to a `Response`.
service::service_fn,
// A function which runs a future to completion using the Hyper runtime.
rt::run,
},
futures::{
// `TokioDefaultSpawner` tells futures 0.3 futures how to spawn tasks
// onto the Tokio runtime.
compat::TokioDefaultSpawner,
// Extension traits providing additional methods on futures.
// `FutureExt` adds methods that work for all futures, whereas
// `TryFutureExt` adds methods to futures that return `Result` types.
future::{FutureExt, TryFutureExt},
},
std::net::SocketAddr,
// This is the redefinition of the await! macro which supports both
// futures 0.1 (used by Hyper and Tokio) and futures 0.3 (the new API
// exposed by `std::future` and implemented by `async fn` syntax).
tokio::await,
};
```
Once the imports are out of the way, we can start putting together the
boilerplate to allow us to serve requests:
```rust
async fn serve_req(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
unimplemented!()
}
async fn run_server(addr: SocketAddr) {
println!("Listening on http://{}", addr);
// Create a server bound on the provided address
let serve_future = Server::bind(&addr)
// Serve requests using our `async serve_req` function.
// `serve` takes a closure which returns a type implementing the
// `Service` trait. `service_fn` returns a value implementing the
// `Service` trait, and accepts a closure which goes from request
// to a future of the response. In order to use our `serve_req`
// function with Hyper, we have to box it and put it in a compatability
// wrapper to go from a futures 0.3 future (the kind returned by
// `async fn`) to a futures 0.1 future (the kind used by Hyper).
.serve(|| service_fn(|req|
serve_req(req).boxed().compat(TokioDefaultSpawner)
));
// Wait for the server to complete serving or exit with an error.
// If an error occurred, print it to stderr.
if let Err(e) = await!(serve_future) {
eprintln!("server error: {}", e);
}
}
fn main() {
// Set the address to run our socket on.
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
// Call our run_server function, which returns a future.
// As with every `async fn`, we need to run that future in order for
// `run_server` to do anything. Additionally, since `run_server` is an
// `async fn`, we need to convert it from a futures 0.3 future into a
// futures 0.1 future.
let futures_03_future = run_server(addr);
let futures_01_future =
futures_03_future.unit_error().boxed().compat(TokioDefaultSpawner);
// Finally, we can run the future to completion using the `run` function
// provided by Hyper.
run(futures_01_future);
}
```
If you `cargo run` now, you should see the message "Listening on
http://127.0.0.1:300" printed on your terminal. If you open that URL in your
browser of choice, you'll see "thread ... panicked at 'not yet implemented'."
Great! Now we just need to actually handle requests. To start, let's just
return a static message:
```rust
async fn serve_req(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
// Always return successfully with a response containing a body with
// a friendly greeting ;)
Ok(Response::new(Body::from("hello, world!")))
}
```
If you `cargo run` again and refresh the page, you should see "hello, world!"
appear in your browser. Congratulations! You just wrote your first asynchronous
webserver in Rust.
You can also inspect the request itself, which contains information such as
the request URI, HTTP version, headers, and other metadata. For example, we
can print out the URI of the request like this:
```rust
println!("Got request at {:?}", req.uri());
```
You may have noticed that we're not yet doing
anything asynchronous when handling the request-- we just respond immediately,
so we're not taking advantage of the flexibility that `async fn` gives us.
Rather than just returning a static message, let's try proxying the user's
request to another website using Hyper's HTTP client.
We start by parsing out the URL we want to request:
```rust
let url_str = "http://www.rust-lang.org/en-US/";
let url = url_str.parse::<Uri>().expect("failed to parse URL");
```
Then we can create a new `hyper::Client` and use it to make a `GET` request,
returning the response to the user:
```rust
let res = await!(Client::new().get(url));
// Return the result of the request directly to the user
println!("request finished --returning response");
res
```
`Client::get` returns a `hyper::client::FutureResponse`, which implements
`Future<Output = Result<Response, Error>>`
(or `Future<Item = Response, Error = Error>` in futures 0.1 terms).
When we `await!` that future, an HTTP request is sent out, the current task
is suspended, and the task is queued to be continued once a response has
become available.
Now, if you `cargo run` and open `http://127.0.0.1:3000/foo` in your browser,
you'll see the Rust homepage, and the following terminal output:
```
Listening on http://127.0.0.1:3000
Got request at /foo
making request to http://www.rust-lang.org/en-US/
request finished-- returning response
```
Congratulations! You just proxied an HTTP request.

View File

@ -0,0 +1,61 @@
## Why Async?
We all love how Rust allows us to write fast, safe software. But why write
asynchronous code?
Asynchonous code allows us to run multiple tasks concurrently on the same OS
thread. In a typical threaded application, if you wanted to download two
different webpages at the same time, you would spread the work across two
different threads, like this:
```rust
fn get_two_sites() {
// Spawn two threads to do work.
let thread_one = thread::spawn(|| download("https:://www.foo.com"));
let thread_two = thread::spawn(|| download("https:://www.bar.com"));
// Wait for both threads to complete.
thread_one.join();
thread_two.join();
}
```
This works fine for many applications-- after, all threads were designed
to do just this: run multiple different tasks at once. However, they also
come with some limitations. There's a lot of overhead involved in the
process of switching between different threads and sharing data between
threads. Even a thread which just sits and does nothing uses up valuable
system resources. These are the costs that asynchronous code is designed
to eliminate. We can rewrite the function above using Rust's
`async`/`await!` notation, which will allow us to run multiple tasks at
once without creating multiple threads:
```rust
async fn get_two_sites() {
// Create a two different "futures" which, when run to completion,
// will asynchronously download the webpages.
let future_one = download_async("https:://www.foo.com");
let future_two = download_async("https:://www.bar.com");
// Run both futures to completion at the same time.
join!(future_one, future_two);
}
```
Overall, asynchronous applications have the potential to be much faster and
use fewer resources than a corresponding threaded implementation. However,
there is a cost. Threads are natively supported by the operating system,
and using them doesn't require any special programming model-- any function
can create a thread, and calling a function that uses threads is usually
just as easy as calling any normal function. However, asynchronous functions
require special support from the language or libraries in order to work.
In Rust, `async fn` creates an asynchronous function which, when called,
will return a future which needs to be run to completion in order for the
body of the function to execute.
It's important to remember that traditional threaded applications can be quite
effective, and that Rust's small memory footprint and predictability mean that
you can get far without ever using `async`. The increased complexity of the
asynchronous programming model isn't always worth it, and it's important to
consider whether your application would be better served by using a simpler
threaded model.

138
src/pinning/chapter.md Normal file
View File

@ -0,0 +1,138 @@
# Pinning
In order to poll futures, they must be pinned using a special type called
`Pin<T>`. If you read the explanation of [the `Future` trait] in the
previous section ["Executing `Future`s and Tasks"], you'll recognise
`Pin` from the `self: Pin<&mut Self>` in the `Future:poll` method's definition.
But what does it mean, and why do we need it?
## Why Pinning
Pinning makes it possible to guarantee that an object won't ever be moved.
To understand why this is necessary, we need remember how `async`/`await!`
works. Consider the following code:
```rust
async {
await!(fut_one);
await!(fut_two);
}
```
Under the hood, this creates an anonymous type that implements `Future`,
providing a `poll` method that looks something like this:
```rust
// The `Future` type generated by our `async { ... }` block
struct AsyncFuture {
fut_one: FutOne,
fut_two: FutTwo,
state: State,
}
// List of states our `async` block can be in
enum State {
AwaitingFutOne,
AwaitingFutTwo,
Done,
}
impl AsyncFuture {
fn poll(...) -> Poll<()> {
loop {
match self.state {
State::AwaitingFutOne => match self.fut_one.poll(..) {
Poll::Ready(()) => self.state = State::AwaitingFutTwo,
Poll::Pending => return Poll::Pending,
}
State::AwaitingFutTwo => match self.fut_two.poll(..) {
Poll::Ready(()) => self.state = State::Done,
Poll::Pending => return Poll::Pending,
}
State::Done => return Poll::Ready(()),
}
}
}
}
```
When `poll` is first called, it will poll `fut_one`. If `fut_one` can't
complete, `AsyncFuture::poll` will return. Future calls to `poll` will pick
up where the previous one left off. This process continues until the future
is able to successfully complete.
However, what happens if we have an `async` block that uses references?
For example:
```rust
async {
let mut x = [0; 128];
let read_into_buf_fut = read_into_buf(&mut x);
await!(read_into_buf_fut);
println!("{:?}", x);
}
```
What struct does this compile down to?
```rust
struct ReadIntoBuf<'a> {
buf: &'a mut [u8], // points to `x` below
}
struct AsyncFuture {
x: [u8; 128],
read_into_buf_fut: ReadIntoBuf<'what_lifetime?>,
}
```
Here, the `ReadIntoBuf` future holds a reference into the other field of our
structure, `x`. However, if `AsyncFuture` is moved, the location of `x` will
move as well, invalidating the pointer stored in `read_into_buf_fut.buf`.
Pinning futures to a particular spot in memory prevents this problem, making
it safe to create references to values inside an `async` block.
## How to Use Pinning
The `Pin` type wraps pointer types, guaranteeing that the values behind the
pointer won't be moved. For example, `Pin<&mut T>`, `Pin<&T>`,
`Pin<Box<T>>` all guarantee that `T` won't be moved.
Most types don't have a problem being moved. These types implement a trait
called `Unpin`. Pointers to `Unpin` types can be freely placed into or taken
out of `Pin`. For example, `u8` is `Unpin`, so `Pin<&mut T>` behaves just like
a normal `&mut T`.
Some functions require the futures they work with to be `Unpin`. To use a
`Future` or `Stream` that isn't `Unpin` with a function that requires
`Unpin` types, you'll first have to pin the value using either
`Box::pinned` (to create a `Pin<Box<T>>`) or the `pin_utils::pin_mut!` macro
(to create a `Pin<&mut T>`). `Pin<Box<Fut>>` and `Pin<&mut Fut>` can both be
used as futures, and both implement `Unpin`.
For example:
```rust
use pin_utils::pin_mut; // `pin_utils` is a handy crate available on crates.io
// A function which takes a `Future` that implements `Unpin`.
fn execute_unpin_future(x: impl Future<Output = ()> + Unpin) { ... }
let fut = async { ... };
execute_unpin_future(fut); // Error: `fut` does not implement `Unpin` trait
// Pinning with `Box`:
let fut = async { ... };
let fut = Box::pinned(fut);
execute_unpin_future(fut); // OK
// Pinning with `pin_mut!`:
let fut = async { ... };
pin_mut!(fut);
execute_unpin_future(fut); // OK
```
["Executing `Future`s and Tasks"]: TODO
[the `Future` trait]: TODO

104
src/streams/chapter.md Normal file
View File

@ -0,0 +1,104 @@
# The `Stream` Trait
The `Stream` trait is similar to `Future` but can yield multiple values before
completing, similar to the `Iterator` trait from the standard library:
```rust
trait Stream {
/// The type of value yielded by the stream.
type Item;
/// Attempt to resolve the next item in the stream.
/// Returns `Poll::Pending` if not ready, `Poll::Ready(Some(x))` if a value
/// is ready, and `Poll::Ready(None)` if the stream has completed.
fn poll_next(self: Pin<&mut Self>, lw: &LocalWaker)
-> Poll<Option<Self::Item>>;
}
```
One common example of a `Stream` is the `Receiver` for the channel type from
the `futures` crate. It will yield `Some(val)` every time a value is sent
from the `Sender` end, and will yield `None` once the `Sender` has been
dropped and all pending messages have been received:
```rust
use futures::channel::mpsc;
use futures::prelude::*;
let fut = async {
let (tx, rx) = mpsc::channel(BUFFER_SIZE);
await!(tx.send(1)).unwrap();
await!(tx.send(2)).unwrap();
drop(tx);
// `StreamExt::next` is similar to `Iterator::next`, but returns a
// type that implements `Future<Output = Option<T>>`.
assert_eq!(Some(1), await!(rx.next()));
assert_eq!(Some(2), await!(rx.next()));
assert_eq!(None, await!(rx.next()));
};
```
## Patterns: Iteration and Concurrency
Similar to synchronous `Iterator`s, there are many different ways to iterate
over and process the values in a `Stream`. There are combinator-style methods
such as `map`, `filter`, and `fold`, and their early-exit-on-error cousins
`try_map`, `try_filter`, and `try_fold`.
Unfortunately, `for` loops are not yet usable with `Stream`s, but for
imperative-style code, `while let` and `.for_each` are available:
```rust
use futures::prelude::*;
let fut = async {
let mut stream: impl Stream<Item = Result<i32, io::Error>> = ...;
// processing with `try_for_each`:
await!(stream.try_for_each(async |item| {
// handle `item`
Ok(())
}))?;
// processing with `while let`:
while let Some(item) = await!(stream.try_next())? {
// handle `item`
}
...
Ok(())
};
```
However, if we're just processing one element at a time, we're potentially
leaving behind opportunity for concurrency, which is, after all, why we're
writing async code in the first place. To process multiple items from a stream
concurrently, use the `for_each_concurrent` and `try_for_each_concurrent`
methods:
```rust
use futures::prelude::*;
let fut = async {
let mut stream: impl Stream<Item = Result<i32, io::Error>> = ...;
await!(stream.try_for_each_concurrent(MAX_CONCURRENT_JUMPERS, async |num| {
await!(jump_n_times(num))?;
await!(report_jumps(num))?;
Ok(())
})?;
...
Ok(())
};
```
This approach allows up to `MAX_CONCURRENT_JUMPERS` to all be jumping at once
(or performing any operation on the items, for that matter-- the API isn't
strictly tied to jumping). If you want to allow an unlimited number of
operations at once, you can use `None` rather than `MAX_CONCURRENT_...`, but
beware that if `stream` comes from untrusted user input, this can allow
badly behaved clients to overload the system with too many simultaneous
requests.