Theory and Design of PL (CS 538)
April 27, 2020
# Generator producing 0, 1, ..., n-1 one at a time
def firstn(n):
num = 0
while num < n:
yield num # return num to caller, suspend execution
num += 1 # resume here next time generator called
gen = firstn(100); # initialize generator
res0 = next(gen); # 0
res1 = next(gen); # 1
res2 = next(gen); # 2
res3 = next(gen); # 3Can we just write “normal” code instead?
let my_async_block = async { 42 }; // you write this
// Compiler generates (something like) this:
enum AsyncState42 { Start, Done };
struct AsyncBlock42 { state: AsyncState42 };
impl Future for AsyncBlock42 {
type Output = i32;
fn poll(&mut self) -> Poll<i32> {
if self.state == Start {
*self.state = Done; Ready(42)
} else {
panic!("Already returned 42")
} } }
let my_async_block = AsyncBlock42 { state: Start };let my_fut = async {
let my_str = my_async_fn(vec![1, 2, 3]);
// ... type of my_str isn't String ...
}my_fut is polled, it doesn’t do anything:
.await after a Future
await in async context!fut is a Future, fut.await means:
fut is Ready (use poll())? after a Resultres is a Result, res? means:
res is Ok(…)let my_fut = async {
let my_str = my_async_fn(vec![1, 2, 3]).await;
// ... do stuff with my_str ...
}my_async_fn
my_strasync fn get_food_order() -> Food { /* ... */ }
async fn get_drink_order() -> Drink { /* ... */ }
async fn make_food(the_food: Food) -> () {
if the_food = Burger {
make_burger.await;
} else {
make_pizza.await;
}
}
async fn make_drink(the_drink: Drink) -> () { /* ... */ }
async fn wash_dishes() -> () { /* ... */ }std::sync::Mutex::lock (all of std::sync)std::fs::read (all of std::fs, std::net)std::thread::sleep (all of std::thread)Never use blocking calls in async code!!!
pub trait Future {
type Output;
fn poll(
self: Pin<&mut Self>, // ignore Pin for now
cx: &mut Context
) -> Poll<Self::Output>;
}Context holds a Waker, argument to pollpoll threads the Waker through
cx alongcx with ReactorWe’ll talk about tokio, though the Rust async ecosystem is evolving rapidly
block_on
task::spawn
spawn_blocking for tasks that may blockpub trait Stream {
type Item;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context
) -> Poll<Option<Self::Item>>;
}Poll<Option<Item>>
NotReady: next item not readyReady(Some(item)): next item readyReady(None): stream finished