Select
Selectという操作では、futureの集合のうち、いずれか1つの準備が整うまで待機し、そのfutureが提供する結果に対して応答します。これはJavaScriptにおけるPromise.raceに似ています。また、Pythonにおける asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED)と比べることができます。
Similar to a match statement, the body of select! has a number of arms, each of the form pattern = future => statement. When a future is ready, its return value is destructured by the pattern. The statement is then run with the resulting variables. The statement result becomes the result of the select! macro.
use tokio::sync::mpsc; use tokio::time::{sleep, Duration}; #[tokio::main] async fn main() { let (tx, mut rx) = mpsc::channel(32); let listener = tokio::spawn(async move { tokio::select! { Some(msg) = rx.recv() => println!("got: {msg}"), _ = sleep(Duration::from_millis(50)) => println!("timeout"), }; }); sleep(Duration::from_millis(10)).await; tx.send(String::from("Hello!")).await.expect("Failed to send greeting"); listener.await.expect("Listener failed"); }
-
The
listenerasync block here is a common form: wait for some async event, or for a timeout. Change thesleepto sleep longer to see it fail. Why does thesendalso fail in this situation? -
select!is also often used in a loop in “actor” architectures, where a task reacts to events in a loop. That has some pitfalls, which will be discussed in the next segment.