Rust’s `async` and `.await` syntax lets asynchronous code retain the shape of ordinary function calls. An `async fn` returns a future: a deferred computation that produces a value when it completes. Calling the function creates the future; it does not, by itself, run the function body. section 10.3 section 10.2
A small file-reading simulation makes the distinction visible. Two functions are spawned as Tokio tasks, but an initial version calls them without `.await`; only the message from `main` appears. Adding `.await` inside each task activates the functions, and `tokio::join!` waits for both tasks to finish. The function with the shorter simulated delay reports its result first. section 10.2
use std::thread::sleep;
use std::time::Duration;
#[tokio::main] #1
async fn main() { #2
println!("Hello before reading file!");
let h1 = tokio::spawn(async { #3
let _file1_contents = read_from_file1(); #3
}); #3
let h2 = tokio::spawn(async { #3
let _file2_contents = read_from_file2();
});
let _ = tokio::join!(h1, h2); #4
}
// function that simulates reading from a file
async fn read_from_file1() -> String { #5
sleep(Duration::new(4, –)); #5
println!("{:?}", "Processing file 1"); #5
String::from("Hello, there from file 1") #5
} #5
// function that simulates reading from a file #5
async fn read_from_file2() -> String { #5
sleep(Duration::new(2, –));
println!("{:?}", "Processing file 2");
String::from("Hello, there from file 2")
}
The first Tokio version spawns tasks but calls the async functions without `.await`, so their file-processing messages do not appear. section 10.2
The pieces have distinct jobs:
- `async fn` or an `async` block defines a computation that returns a future. A function declared `async fn read_from_file1() -> String` can also be written as a function returning `impl Future<Output = String>` with an `async` block. section 10.3
- `.await` activates an async function call in the demonstrated tasks. Without it, assigning the returned future is not the same as obtaining the function’s `String` result. section 10.2
- The Tokio runtime schedules spawned tasks; `#[tokio::main]` supplies the runtime for `main`, and `tokio::join!` waits for the spawned tasks. Tasks may be scheduled on the current thread or different threads, depending on runtime configuration. section 10.2
Under the syntax is the `Future` trait. Its `poll` method can report `Poll::Pending` or `Poll::Ready(value)`. This is why a future represents work that may not have produced its eventual value yet. The file-reading walkthrough uses `std::thread::sleep` to simulate a delay; that blocking call should not be mistaken for non-blocking I/O. section 10.3 section 10.2
The server-side use is an asynchronous request handler. An Actix Web route can direct `GET /health` to `pub async fn health_check_handler() -> impl Responder`. Actix supports asynchronous I/O so a worker can do other work while waiting on network I/O; it also uses OS-native worker threads for parallelism. Actix Web supplies an async runtime built on Tokio, so application code does not need to set up the standalone example’s runtime in the same way. section 3.1.2 section 10.3
pub async fn health_check_handler() -> impl Responder {
HttpResponse::Ok().json("Hello, EzyTutors is alive and kicking")
}
The health-check handler shows `async fn` in an Actix Web endpoint that returns an HTTP response. section 3.1.2
















