Rust

Article & Tutorial

Async Rust with Tokio: Futures, async/await, Tasks, Timers and Channels

Learn async Rust with Tokio, futures, async/await, tasks, timers, select, channels, blocking work and practical asynchronous service patterns.

Async Rust with Tokio, futures, tasks, timers and channels
Async Rust with Tokio, futures, tasks, timers and channels
Contents

1. async functions return futures

1. async functions return futures async fn fetch_name() -> String { String::from("Melochip") } Calling an async function creates a future. The future makes progress when it is polled by an executor/runtime. 2. Start a Tokio runtime [dependencies] tokio = { version = "1", features = ["full"] } #[tokio::main] async fn main() { println!("async Rust"); } 3. await asynchronous work async fn answer() -> u32 { 42 } #[tokio::main] async fn main() { let value = answer().await; println!("{value}"); } 4. Spawn concurrent tasks let task = tokio::spawn(async { 21 * 2 }); let result = task.await.unwrap(); Tokio tasks are lightweight scheduled units of asynchronous work. They are not identical to creating one OS thread per task. 5. Run independent operations concurrently let (users, orders) = tokio::join!(load_users(), load_orders()); join! waits for multiple futures together. 6. Timers use tokio::time::{sleep, Duration}; sleep(Duration::from_millis(250)).await; An async sleep yields to the runtime rather than blocking the worker thread. 7. Timeouts use tokio::time::{timeout, Duration}; let result = timeout(Duration::from_secs(2), perform_request()).await; Timeouts are essential around external dependencies so a slow service cannot hold resources indefinitely. 8. select! tokio::select! { value = receive_message() => println!("message: {value:?}"), _ = tokio::time::sleep(Duration::from_secs(5)) => println!("timeout"), } select! lets you react to whichever async branch completes first. 9. Async channels let (tx, mut rx) = tokio::sync::mpsc::channel(32); tokio::spawn(async move { tx.send("job").await.unwrap(); }); if let Some(job) = rx.recv().await { println!("{job}"); } Bounded channels provide backpressure when producers are faster than consumers. 10. Do not block the async runtime CPU-heavy or blocking operations can starve other async tasks. Use an async API where possible, or move unavoidable blocking work: let result = tokio::task::spawn_blocking(|| { expensive_blocking_operation() }).await?; 11. Shared async state Tokio provides asynchronous synchronization primitives such as tokio::sync::Mutex. Do not automatically replace every standard mutex with an async mutex; choose based on whether a guard must be held across .await. 12. Cancellation Dropping many futures cancels the pending operation. Design cleanup and transactional behavior with cancellation in mind, especially when a future performs several external side effects. 13. Structured error handling async fn process() -> Result<(), Box> { let data = load().await?; save(data).await?; Ok(()) } 14. Practical worker example use tokio::sync::mpsc; #[tokio::main] async fn main() { let (tx, mut rx) = mpsc::channel(10); for id in 1..=3 { tx.send(id).await.unwrap(); } drop(tx); while let Some(id) = rx.recv().await { tokio::spawn(async move { println!("processing job {id}"); }); } }

15. Common mistakes

15. Common mistakes • Calling blocking filesystem/network/database APIs from async tasks. • Spawning unlimited tasks without backpressure. • Holding locks across .await unnecessarily. • Ignoring timeouts and cancellation. • Using async for purely CPU-bound code where threads or parallel iterators may be clearer. Mini lab Build an async job simulator with a bounded Tokio channel. Send 20 jobs, process them concurrently with a fixed concurrency limit, add a timeout, and record successful/failed jobs. Key takeaways async/await describes asynchronous work; Tokio provides the runtime that drives it. Build bounded systems with timeouts, backpressure and explicit error handling rather than simply spawning unlimited tasks.

Did this help?

Yes No

Join the discussion

0 Comments

Ask questions, add context, or share what worked.

Sign in to join the discussion

No comments yet. Start the discussion.

More from Melochip Editorial

Related articles

Stay in the loop. Get new Melochip articles

Receive Melochip article updates when new articles are available. Explicit opt-in only.

No pre-checked boxes. Unsubscribe support is part of the subscriber foundation.