select! waits for the first branch to complete.
rustuse tokio::select; let result = select! { val = task_a() => { println!("A finished first: {val}"); val } val = task_b() => { println!("B finished first: {val}"); val } };
Timeout Pattern
rustuse tokio::time::{timeout, Duration}; match timeout(Duration::from_secs(5), slow_operation()).await { Ok(result) => println!("Got: {result:?}"), Err(_) => println!("Timed out!"), } // Or with select! select! { result = slow_operation() => println!("Result: {result:?}"), _ = tokio::time::sleep(Duration::from_secs(5)) => println!("Timeout!"), }
Cancellation
When one branch completes, others are dropped (cancelled):
rustselect! { _ = operation_a() => println!("A won"), _ = operation_b() => println!("B won"), } // The losing operation is cancelled!
Biased Selection
By default, select! randomly picks a ready branch. Use biased; for priority:
rustselect! { biased; _ = high_priority() => { }, // Checked first _ = low_priority() => { }, // Checked second }
Loop with select!
rustloop { select! { Some(msg) = rx.recv() => handle(msg), _ = shutdown_signal.recv() => { println!("Shutting down"); break; } } }
See Select.
Code Examples
rust
use tokio::{select, signal};
async fn graceful_shutdown() {
let mut interval = tokio::time::interval(Duration::from_secs(1));
loop {
select! {
_ = interval.tick() => {
println!("Tick!");
do_periodic_work().await;
}
_ = signal::ctrl_c() => {
println!("Received Ctrl+C, shutting down...");
cleanup().await;
break;
}
}
}
}