Rust
select!
Wait on multiple futures at once with tokio::select!.
select!
tokio::select! waits on several futures at once and runs the arm of the first to complete; the others are cancelled. It's the basis of timeout and cancellation patterns:
tokio::select! {
mesaj = rx.recv() => println!("geldi: {mesaj:?}"),
_ = tokio::time::sleep(Duration::from_secs(1)) => println!("zaman aşımı"),
_ = tokio::signal::ctrl_c() => println!("kapatılıyor"),
}
There's a shorter tool just for timeouts: tokio::time::timeout(duration, future).await.
std counterpart: waiting with a timeout
With std channels, recv_timeout sets up a "race" between a message and a duration:
use std::sync::mpsc::{self, RecvTimeoutError};
use std::time::Duration;
match rx.recv_timeout(Duration::from_millis(500)) {
Ok(m) => println!("geldi: {m}"),
Err(RecvTimeoutError::Timeout) => println!("zaman aşımı"),
Err(RecvTimeoutError::Disconnected) => println!("gönderici kapandı"),
}
Exercise Timeout
Let a thread sleep 10 ms and send "hazır"; receive it with recv_timeout(500 ms). On a second channel, keep the sender alive but send nothing, and wait with recv_timeout(10 ms). Print both results with {:?}, separated by a space.
Show example solution
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(10));
tx.send("hazır").unwrap();
});
let a = rx.recv_timeout(Duration::from_millis(500));
let (_tx2, rx2) = mpsc::channel::<&str>();
let b = rx2.recv_timeout(Duration::from_millis(10));
println!("{:?} {:?}", a, b);
}
Test yourself
-
What happens to the losing future in select!?
- Panic
- It's dropped; its half-done work is cancelled
- It completes in the background
- It continues in the next select!
Show answer
It's dropped; its half-done work is cancelled — That's why it matters that the futures in select! are cancel-safe.
-
Wait with a deadline
match rx.____(Duration::from_millis(500)) {
Ok(m) => println!("{m}"),
Err(_) => println!("zaman aşımı"),
}
Show answer
match rx.recv_timeout(Duration::from_millis(500)) {
Ok(m) => println!("{m}"),
Err(_) => println!("zaman aşımı"),
}
-
Case and result
- Message before the deadline
- Ok(message)
- Time ran out
- Err(Timeout)
- Sender closed
- Err(Disconnected)
- select! kaybeden
- Dropped
Next lesson: Summary - Tokio