Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

JoinSet scheduling

Earlier it was mentioned that a task starts running when it is added to a JoinSet using the spawn function, but I wanted to have an example to really see it.

So in this example we launch to tasks using spawn and then we call sleep to let some time pass. Looking at the output you can see that faster running task (the one that uses a 1 second sleep as a fake wait for IO) finished before the first 2-second sleep is over.

Then we sleep another 2 seconds and by that time the task that takes 3 seconds has also finished.

async fn say(text: &str, sec: u64) {
    tokio::time::sleep(tokio::time::Duration::from_secs(sec)).await;
    println!("{text}");
}


#[tokio::main]
async fn main() {
    let start = std::time::Instant::now();
    println!("start");

    let mut tasks = tokio::task::JoinSet::new();
    tasks.spawn(say("Hello", 3));
    tasks.spawn(say("Hi", 1));
    println!("launched both");

    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    println!("waited");

    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    println!("waited again");

    tasks.join_all().await;
    println!("done");

    let elapsed = start.elapsed();
    println!("Elapsed: {:.2?}", elapsed);
}

The output

start
launched both
Hi
waited
Hello
waited again
done
Elapsed: 4.00s

Cargo.toml

[package]
name = "demo"
version = "0.1.0"
edition = "2024"

[dependencies]
tokio = { version = "1.47.1", features = ["full"] }

  • JoinSet
  • spawn
  • join_all