The Talk you’ve been .await-ing for
@steveklabnik
The Talk youve been .await-ing for @steveklabnik async fn foo(s: - - PowerPoint PPT Presentation
The Talk youve been .await-ing for @steveklabnik async fn foo(s: String) -> i32 { // } fn foo(s: String) -> impl Future<Output=i32> { // } Stuff were going to talk about async/await and Futures Generators:
The Talk you’ve been .await-ing for
@steveklabnik
async fn foo(s: String) -> i32 { // … } fn foo(s: String) -> impl Future<Output=i32> { // … }
Stuff we’re going to talk about
async/await and Futures
Async/await is simpler syntax for Futures
Async/await is simpler syntax for Futures*
A Future represents a value that will exist sometime in the future
Let’s build a future!
A timer future
amount of time
true and ‘wakes up’ the future
done
For using async/await
async fn foo(s: String) -> i32 { // … } fn foo(s: String) -> impl Future<Output=i32> { // … }
If you have a Future<Output=i32> and you want an i32, use .await on it
You can only .await inside of an async fn or block
To start executing a Future, you pass it to an executor
Generators aka stackless coroutines
Generators are not stable … yet
Futures need to have poll() called over and
Generators let you call yield over and over to get values async/await is a simpler syntax for a generator that implements the Future trait
Tasks, Executors, & Reactors
“The event loop”
Task: a unit of work to execute, a chain of Futures Executor: schedules tasks Reactor: notifies the executor that tasks are ready to execute
Interface to the reactor Executor calls poll, and provides a context
Let’s build an executor!
async fn foo() { // … }
async fn foo() { // … } spawner.spawn(foo())
async fn foo() { // … } spawner.spawn(foo()) Executor task queue
async fn foo() { // … } spawner.spawn(foo()) Executor task queue
Calls poll() on the Future
async fn foo() { // … } spawner.spawn(foo()) Executor task queue
Calls poll() on the Future
async fn foo() { // … } spawner.spawn(foo()) Executor task queue
Calls poll() on the Future
Future calls wake() (reactor)
async fn foo() { // … } spawner.spawn(foo()) Executor task queue
Calls poll() on the Future
Future calls wake() (reactor)
A quick aside about Pin<P>
Before a future starts executing, we need to be able to move it around in memory. (For example, to create a task out of it, we need to move it to the heap) Once a future starts executing, it must not move in memory. (otherwise, borrows in the body of the future would become invalid)
When you turn some sort of pointer type into a Pin<P>, you’re promising that what the pointer to will no longer move. Box<T> turns into Pin<Box<T>> There’s an extra trait, “Unpin”, that says “I don’t care about this”, similar to how Copy says “I don’t care about move semantics.
Let’s build a reactor!
(We’re not gonna build a reactor)
(We technically did build a reactor)
Bonus round: async fn in traits
A function is only one function A trait is implemented for many types, and so is many functions
It gets way more complicated
It gets way way way more complicated
Thanks!
@steveklabnik