select!
- Rust course
- Advanced
- Lesson 11/81
- 4 min
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ı"),
}Practice 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.
Starter code
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
// buraya yaz
}Sample 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);
}Expected output
Ok("hazır") Err(Timeout)
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What happens to the losing future in select!?
- Panic
- It's dropped; its half-done work is cancelled Correct answer
- It completes in the background
- It continues in the next select!
Explanation: That's why it matters that the futures in select! are cancel-safe.
2 Wait with a deadline
match rx.____(Duration::from_millis(500)) {
Ok(m) => println!("{m}"),
Err(_) => println!("zaman aşımı"),
}
match rx.recv_timeout(Duration::from_millis(500)) {
Ok(m) => println!("{m}"),
Err(_) => println!("zaman aşımı"),
}
Explanation: recv_timeout returns a Timeout error when the time runs out.
3 Case and result
| Term | Meaning |
|---|---|
Message before the deadline |
Ok(message) |
Time ran out |
Err(Timeout) |
Sender closed |
Err(Disconnected) |
select! kaybeden |
Dropped |