CodeBlanks Logo Icon CodeBlanks

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ı"),
}

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

main.rs
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    // buraya yaz
}

Sample solution

main.rs
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

Question
match rx.____(Duration::from_millis(500)) {
    Ok(m) => println!("{m}"),
    Err(_) => println!("zaman aşımı"),
}
Answer
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

All lessons in Advanced