Async Concepts
Async Function
Future Then Result
Calling an async fn creates a future. A small executor can poll an immediately-ready future to get the result.
Program
Play the program to choose a base value, create a future, and resolve it into points.
async_function.rs
Replay: real traced execution (multi-file project)
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn main() {
let base = 8;
let future = load_points(base);
let points = block_on(future);
println!("{points}");
}
async fn load_points(base: i32) -> i32 {
base + 4
}
fn block_on<F: Future>(future: F) -> F::Output {
let waker = noop_waker();
let mut context = Context::from_waker(&waker);
let mut future = pin!(future);
loop {
match future.as_mut().poll(&mut context) {
Poll::Ready(value) => return value,
Poll::Pending => {}
}
}
}
fn noop_waker() -> Waker {
unsafe { Waker::from_raw(noop_raw_waker()) }
}
fn noop_raw_waker() -> RawWaker {
RawWaker::new(std::ptr::null(), &VTABLE)
}
static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn main() {
let base = 3;
let future = load_points(base);
let points = block_on(future);
println!("{points}");
}
async fn load_points(base: i32) -> i32 {
base + 4
}
fn block_on<F: Future>(future: F) -> F::Output {
let waker = noop_waker();
let mut context = Context::from_waker(&waker);
let mut future = pin!(future);
loop {
match future.as_mut().poll(&mut context) {
Poll::Ready(value) => return value,
Poll::Pending => {}
}
}
}
fn noop_waker() -> Waker {
unsafe { Waker::from_raw(noop_raw_waker()) }
}
fn noop_raw_waker() -> RawWaker {
RawWaker::new(std::ptr::null(), &VTABLE)
}
static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
fn main() {
let base = 12;
let future = load_points(base);
let points = block_on(future);
println!("{points}");
}
async fn load_points(base: i32) -> i32 {
base + 4
}
fn block_on<F: Future>(future: F) -> F::Output {
let waker = noop_waker();
let mut context = Context::from_waker(&waker);
let mut future = pin!(future);
loop {
match future.as_mut().poll(&mut context) {
Poll::Ready(value) => return value,
Poll::Pending => {}
}
}
}
fn noop_waker() -> Waker {
unsafe { Waker::from_raw(noop_raw_waker()) }
}
fn noop_raw_waker() -> RawWaker {
RawWaker::new(std::ptr::null(), &VTABLE)
}
static VTABLE: RawWakerVTable = RawWakerVTable::new(|_| noop_raw_waker(), |_| {}, |_| {}, |_| {});
base ← 8, future ← (empty)
5fn main() {6 let bas→ 8e = 8; //@base=8, 3, 127 let futur→ (empty)e = load_points(bas8e);8 let points = block_on(futur(empty)e);9 println!("{points}");waker ← Waker { data: 0x0, vtable: ⟨addr A⟩ }, context ← Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }
16fn block_on<F: Future>(future: F) -> F::Output {17 let wake→ Waker { data: 0x0, vtable: ⟨addr A⟩ }r = noop_waker();18 let mut contex→ Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }t = Context::from_waker(&wakeWaker { data: 0x0, vtable: ⟨addr A⟩ }r);19 let mut futur→ (empty)e = pin!(future);20 loop {fn load_points(base: i32) -> i32
12async fn load_points(base: i32) -> i32 {13 bas8e + 414}points ← 12
7 let future = load_points(base);8 let point→ 12s = block_on(futur(empty)e);9 println!("{points}");10}output12
base ← 3, future ← (empty)
5fn main() {6 let bas→ 3e = 3;7 let futur→ (empty)e = load_points(bas3e);8 let points = block_on(futur(empty)e);9 println!("{points}");waker ← Waker { data: 0x0, vtable: ⟨addr A⟩ }, context ← Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }
16fn block_on<F: Future>(future: F) -> F::Output {17 let wake→ Waker { data: 0x0, vtable: ⟨addr A⟩ }r = noop_waker();18 let mut contex→ Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }t = Context::from_waker(&wakeWaker { data: 0x0, vtable: ⟨addr A⟩ }r);19 let mut futur→ (empty)e = pin!(future);20 loop {fn load_points(base: i32) -> i32
12async fn load_points(base: i32) -> i32 {13 bas3e + 414}points ← 7
7 let future = load_points(base);8 let point→ 7s = block_on(futur(empty)e);9 println!("{points}");10}output7
base ← 12, future ← (empty)
5fn main() {6 let bas→ 12e = 12;7 let futur→ (empty)e = load_points(bas12e);8 let points = block_on(futur(empty)e);9 println!("{points}");waker ← Waker { data: 0x0, vtable: ⟨addr A⟩ }, context ← Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }
16fn block_on<F: Future>(future: F) -> F::Output {17 let wake→ Waker { data: 0x0, vtable: ⟨addr A⟩ }r = noop_waker();18 let mut contex→ Context { waker: Waker { data: 0x0, vtable: ⟨addr A⟩ } }t = Context::from_waker(&wakeWaker { data: 0x0, vtable: ⟨addr A⟩ }r);19 let mut futur→ (empty)e = pin!(future);20 loop {fn load_points(base: i32) -> i32
12async fn load_points(base: i32) -> i32 {13 bas12e + 414}points ← 16
7 let future = load_points(base);8 let point→ 16s = block_on(futur(empty)e);9 println!("{points}");10}output16
async fn
Calling an `async fn` creates a future instead of running the body immediately.
Future
A future represents work that can be polled until it returns `Ready`.
executor
`block_on` is a tiny executor for these immediately-ready teaching examples.