Rust Tokio Time
Tokio time is a set of timers that pause one task, not a whole thread. sleep pauses a task for one span of time.
sleep pauses one task
tokio::time::sleep pauses the task, not the thread โ the runtime stays free for other tasks while this one waits:
sleep(Duration::from_millis(50)).await;
println!("woke up after 50 ms");A sleep does nothing until you await it
sleep is a future: the pause happens at the .await, not when the future is made:
let nap = sleep(Duration::from_millis(50)); // nothing happens yet
nap.await; // the pause happens hereinterval ticks at a steady rhythm
Use interval for repeating work. If your code falls behind, the default behaviour is to fire the missed ticks back-to-back until it catches up:
let mut ticker = interval(Duration::from_millis(20));
for _ in 0..3 {
ticker.tick().await;
println!("tick");
}timeout puts a deadline around a job
If the future is too slow, timeout returns Err โ and the future is dropped:
let result = timeout(Duration::from_millis(10), sleep(Duration::from_secs(5))).await;
match result {
Ok(()) => println!("finished in time"),
Err(_) => println!("too slow - gave up"),
}An Instant plus a Duration is a deadline
Instant is Tokio's clock value. Add a Duration to now, and you have the moment by which a job must finish:
let deadline = Instant::now() + Duration::from_millis(100);
println!("deadline set = {}", deadline > Instant::now());sleep_until waits for a moment
sleep waits for a span of time. sleep_until waits until a moment. That is the waiting half of a deadline:
let moment = Instant::now() + Duration::from_millis(30);
sleep_until(moment).await;
println!("the moment arrived");Example
// Cargo.toml: tokio = { version = "1", features = ["full"] }
use tokio::time::{sleep, timeout, Duration};
#[tokio::main]
async fn main() {
sleep(Duration::from_millis(50)).await;
println!("woke up after 50 ms");
let slow = timeout(Duration::from_millis(10), sleep(Duration::from_secs(5))).await;
match slow {
Ok(()) => println!("finished in time"),
Err(_) => println!("too slow - gave up after 10 ms"),
}
}Key points
- Timers cost almost nothing: one runtime can hold thousands of sleeping tasks
- Choose what a missed tick means with set_missed_tick_behavior.
- Burst fires the missed ticks until caught up.
- That is the default.
- Skip drops them and waits for the next scheduled tick.
- Delay waits a full period from the late tick.
In this example, the first sleep pauses the task for 50 milliseconds while the runtime stays free for other work. Then timeout wraps a five-second sleep in a ten-millisecond deadline. The deadline wins, timeout returns Err, and the long sleep is dropped โ the program does not wait five seconds.
Note
Never use std::thread::sleep inside a task โ it blocks the worker thread for everyone, as the Blocking lesson showed.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Rust Playground
Exercise
timeout(10ms, job).await returns Err. What happened to job?