Lesson 22 / 25
Async Rust at a Glance
Futures, executors and await.
Many tasks, few threads
For I/O-heavy servers handling thousands of connections, async Rust uses async fn and .await to write non-blocking code. Futures do nothing until polled by an executor (runtime) such as Tokio, which schedules many tasks on a small pool of threads. Frameworks like Axum and Actix Web build on it. Async adds complexity (pinning, Send bounds across awaits), so use threads for CPU-bound work and async for high-concurrency I/O.
An async HTTP handler with Tokio and Axum (sketch)
Needs the tokio and axum crates; not run here because these examples use only the standard library offline.
use axum::{routing::get, Router};
async fn health() -> &'static str {
"ok"
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/health", get(health));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}Do not block inside async tasks
CPU-heavy or blocking calls inside async code stall the runtime; move them to spawn_blocking or a thread.
Quick check: What runs async futures in Rust?
- Nothing; futures run when created
- The compiler at build time
- The operating system automatically
- An executor (runtime) such as Tokio
Answer
An executor (runtime) such as Tokio — Futures are lazy until polled.