The select! macro polls multiple async operations concurrently and proceeds with whichever one completes first:
use tokio::time::{sleep, Duration};
async fn operation1() -> &'static str {
sleep(Duration::from_millis(100)).await;
"Operation 1"
}
async fn operation2() -> &'static str {
sleep(Duration::from_millis(50)).await;
"Operation 2"
}
#[tokio::main]
async fn main() {
tokio::select! {
result = operation1() => {
println!("Got: {}", result);
}
result = operation2() => {
println!("Got: {}", result);
}
}
}tokio::select! {
result = operation1() => {
println!("Got: {}", result);
}
result = operation2() => {
println!("Got: {}", result);
}
}-
Both futures start concurrently:
select!begins polling bothoperation1()andoperation2()at the same time -
The race:
operation1()sleeps for 100msoperation2()sleeps for 50ms
-
First completion wins: After 50ms,
operation2()completes first and returns"Operation 2" -
Winner takes all: The second branch executes, printing
"Got: Operation 2" -
Loser is cancelled:
operation1()is dropped/cancelled - it never finishes its 100ms sleep or returns its value
- Only one branch executes - whichever future completes first
- The slower operation is cancelled -
operation1()never completes - Each branch has its own scope - that's why using
resultin both branches is fine (they're in separate scopes) - Non-deterministic if timings were equal - if both completed at the same time, either branch could run
This is useful for timeout patterns, racing multiple data sources, or cancelling slow operations.
Got: Operation 2
Since operation2() completes in 50ms while operation1() takes 100ms, operation2() will always win the race and its branch will execute.