liveBook · Manning

Async/await

As explained in Rust Servers, Services, and Apps

An async function is a function whose execution can suspend while awaiting asynchronous operations and later resume.

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

How Rust Servers, Services, and Apps covers it

How deep it goes
Explains lazy execution, `.await`, future-returning syntax, and `Future::poll`, without implementing a runtime.
Examples
Contrasts an unawaited file-reading simulation with awaited Tokio tasks, then shows an Actix Web health-check handler.
What it assumes
Assumes familiarity with Rust functions and basic program execution while introducing futures and runtime behavior through examples.
What you can do after
Apply it via Tokio to await spawned computations and via Actix Web to define asynchronous request handlers.
How it connects
Connects async/await to futures, Tokio tasks, non-blocking I/O, and Actix Web handlers.

Also explained in

Compare how 17 books explain async/await →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust Servers, Services, and Apps. The section links point to the parts of the book it draws on.