patternrusttokioModerate
async/await patterns: spawning tasks and joining futures
Viewed 0 times
tokio 1.x
asyncawaitjoinspawnconcurrentselectJoinHandlecancel
Error Messages
Problem
Developers run async tasks sequentially with .await when they should run concurrently, or misuse spawn and lose track of task handles.
Solution
Use tokio::join! for concurrent futures and tokio::spawn for independent tasks:
use tokio::time::{sleep, Duration};
async fn task_a() -> &'static str { sleep(Duration::from_millis(100)).await; "A" }
async fn task_b() -> &'static str { sleep(Duration::from_millis(100)).await; "B" }
// Sequential — takes 200ms
async fn sequential() {
let a = task_a().await;
let b = task_b().await;
println!("{} {}", a, b);
}
// Concurrent — takes ~100ms
async fn concurrent() {
let (a, b) = tokio::join!(task_a(), task_b());
println!("{} {}", a, b);
}
// Spawned task runs independently
async fn spawned() {
let handle = tokio::spawn(async {
sleep(Duration::from_millis(50)).await;
42u32
});
// Do other work here...
let result = handle.await.unwrap(); // JoinError if task panicked
println!("Result: {}", result);
}Why
Futures in Rust are lazy — awaiting them one by one is sequential. tokio::join! polls multiple futures on the same task concurrently. tokio::spawn creates a new task that can run on a different thread.
Gotchas
- tokio::select! races futures and cancels the others when one completes — ensure futures are cancel-safe
- Spawned tasks must be 'static + Send — they cannot hold non-Send types like Rc or RefCell
- Dropping a JoinHandle does not cancel the task — call handle.abort() to cancel explicitly
Revisions (0)
No revisions yet.