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?