I think I'm missing something very basic. My expectation is that when tick.tick()
completes and starts the sleep
loop, tokio::time::sleep(...).await
should yield back to the select statement, allowing longer_tick
a chance to complete. But once the shorter tick completes, this gets stuck in the sleep loop, never yielding back to select.
use std::time::Duration;
use tokio::time::interval;
#[tokio::main]
async fn main() {
let mut tick = interval(Duration::from_millis(500));
let mut longer_tick = interval(Duration::from_millis(1000));
loop {
tokio::select! {
_ = longer_tick.tick() => {
println!("longer tick");
},
_ = tick.tick() => {
println!("sleeping");
sleep().await;
},
}
}
}
async fn sleep() {
let mut idx = 0;
loop {
let time = idx.min(5);
println!("Sleeping for {} s", time);
tokio::time::sleep(Duration::from_secs(time)).await;
idx += 1;
}
}
Tokio's select only waits for the futures in the branch section, not the handler. So the sleep
future is not considered when using select!
.
Also, per the documentation
Waits on multiple concurrent branches, returning when the first branch completes, cancelling the remaining branches.
When one of the branch completes (the interval
's in this case), the other branches are cancelled.
Therefore when you are using select
, it will only ever execute one of the branch handlers.