Serving HTTP requests
Querying a database
A game render and input loop
Event loops in embedded systems
“Crack then fry the eggs. Meanwhile, fry the bacon for five minutes, or until crispy.”
fn breakfast() { cook_eggs(); fry_bacon(); }
fn cook_eggs() { crack_eggs(); fry_eggs(); } fn crack_eggs() { println!("Started cracking egg."); random_sleep(); println!("Finished cracking egg."); } fn random_sleep() { ... } fn fry_eggs() { ... } // Prints and sleeps fn fry_bacon() { ... } // Prints and sleeps
Started cracking egg. Finished cracking egg. Started frying egg. Finished frying egg. Started frying bacon. Finished frying bacon.
async fn breakfast() { cook_eggs().await; fry_bacon().await; }
async fn cook_eggs() { crack_eggs().await; fry_eggs().await; } async fn crack_eggs() { println!("Started cracking egg."); random_sleep().await; println!("Finished cracking egg."); } async fn fry_eggs() { ... } async fn fry_bacon() { ... } async fn random_sleep() { ... }
Started cracking egg. Finished cracking egg. Started frying egg. Finished frying egg. Started frying bacon. Finished frying bacon.
“Meanwhile, fry the bacon.”
async fn breakfast() { join!(cook_eggs(), fry_bacon()); }
Started frying bacon. Started cracking egg. Finished cracking egg. Started frying egg. Finished frying bacon. Finished frying egg.
“Fry bacon for five minutes, or until crispy.”
async fn fry_bacon() { println!("Started frying bacon."); // This is simplified select! { () = timer() => (), () = crisp_bacon() => () }; println!("Finished frying bacon."); } async fn timer() { ... } async fn crisp_bacon() { ... }
Started frying bacon. Started timer. Started crisping bacon. Finished timer. Finished frying bacon.
“Cook the eggs using a spoon: use a spoon to crack them and then fry them. Meanwhile, use a spoon to fry the bacon.”
async fn breakfast() { let mut spoon = find_spoon(); join!(cook_eggs(&mut spoon), fry_bacon(&mut spoon)) } async fn cook_eggs(spoon: &mut Spoon) { ... } async fn fry_bacon(spoon: &mut Spoon) { ... }
type SpoonMutex = Arc<Mutex<Spoon>>; async fn cook_eggs(spoon_mutex: SpoonMutex) { let spoon = spoon_mutex.lock().await; ... drop(spoon); } async fn fry_bacon(spoon_mutex: SpoonMutex) { ... }
async fn breakfast() { let spoon_mutex = find_spoon(); join!(cook_eggs(spoon_mutex.clone()), fry_bacon(spoon_mutex)) }
Started cracking egg. Finished cracking egg. Started frying egg. Finished frying egg. Started frying bacon. Finished frying bacon.
“Cook the eggs using a spoon: use a spoon to crack them and then fry them using a pan. Meanwhile, use a spoon and use a pan to fry the bacon.”
async fn cook_eggs(spoon_mutex: SpoonMutex, pan_mutex: PanMutex) { let spoon = spoon_mutex.lock().await; crack_eggs().await; let pan = pan_mutex.lock().await; fry_eggs().await; drop(spoon); drop(pan); }
async fn fry_bacon(spoon_mutex: SpoonMutex, pan_mutex: PanMutex) { join!(spoon_mutex.lock(), pan_mutex.lock()); ... drop(spoon); drop(pan); }
Started cracking egg. Finished cracking egg.
let (spoon, pan) = loop { let maybe_spoon = try_lock_spoon(&spoon_mutex).await; let maybe_pan = try_lock_pan(&pan_mutex).await; match (maybe_spoon, maybe_pan) { (Some(spoon), None) => drop(spoon), (None, Some(pan)) => drop(pan), (Some(spoon), Some(pan)) => break (spoon, pan), (None, None) => (), } };
async fn fry_eggs(...) { let (spoon, pan) = loop {...} ... } async fn fry_bacon(...) { let (spoon, pan) = loop {...} ... }
Started cracking egg. Finished cracking egg.
type SpoonAndPanMutex = Arc<Mutex<(Spoon, Pan)>>;
async fn cook_eggs(mutex: SpoonAndPanMutex) { let spoon_and_pan = mutex.lock().await; ... drop(spoon_and_pan); } async fn fry_bacon(mutex: SpoonAndPanMutex) { let spoon_and_pan = mutex.lock().await; ... drop(spoon_and_pan); }
let (sender, receiver) = channel::<Message>(42);
async fn chef_actor(mut receiver: Receiver<Message>) { let mut spoon = Spoon; // internal mutable state let mut pan = Pan; while let Some(msg) = receiver.next().await { ... } }
match msg { // use the state CrackEggs => crack_eggs(&mut spoon).await, FryEggs => fry_eggs(&mut spoon, &mut pan).await, FryBacon => fry_bacon(&mut spoon, &mut pan).await, }
async fn crack_eggs(spoon: &mut Spoon) { .. } async fn fry_eggs(spoon: &mut Spoon, pan: &mut Pan) { ... } async fn fry_bacon(spoon: &mut Spoon, pan: &mut Pan) { ... }
async fn send_cook_eggs(mut sender: Sender<Message>) { sender.send(CrackEggs).await; sender.send(FryEggs).await; } async fn send_fry_bacon(mut sender: Sender<Message>) { sender.send(FryBacon).await; }
async fn breakfast() { let (sender, receiver) = channel::<Message>(42); join!( chef_actor(receiver), send_cook_eggs(sender.clone()), send_fry_bacon(sender), ); }
“He fixes radios by thinking!”
— Surely You're Joking, Mr. Feynman!