liveBook · Manning

Concurrency

As explained in Rust Servers, Services, and Apps

Concurrent programming is the design of programs whose multiple operations can make progress during overlapping periods of time.

Concurrency lets different parts of a program make progress out of order without changing the intended outcome. Parallelism is the narrower case in which tasks execute at the same time. Both matter when many HTTP requests arrive together: a service must respond efficiently without sacrificing safety or latency. section 10.1 section 1.2.1

Two approaches are multithreading and async I/O. Operating-system threads can run independent work concurrently; an async runtime schedules tasks so a thread can do other work while an I/O operation waits. In Actix Web, the HTTP server starts multiple worker threads, each running an application instance, and also uses async I/O. Handlers can access application state through the framework’s safe state mechanism. section 3.3 section 10.6

Two independent file reads

Start with two simulated file reads that take four and two seconds. Called sequentially, they delay the program for six seconds in total. Move each read into a separate `std::thread::spawn` call, then `join` both handles: the waits overlap, so completion takes substantially less time. This example uses native threads; its simulated reads use `sleep`, not actual file I/O. section 10.2

use std::thread;
use std::thread::sleep;
use std::time::Duration;
 
fn main() {
    println!("Hello before reading file!");
    let handle1 = thread::spawn(|| {                #1
        let file1_contents = read_from_file1();
        println!("{:?}", file1_contents);
    });
    let handle2 = thread::spawn(|| {                #2
        let file2_contents = read_from_file2();
        println!("{:?}", file2_contents);
    });
    handle1.join().unwrap();                        #3
    handle2.join().unwrap();                        #4
}
 
// function that simulates reading from a file
fn read_from_file1() -> String {
    sleep(Duration::new(4, –));
    String::from("Hello, there from file 1")
}
 
// function that simulates reading from a file
fn read_from_file2() -> String {
    sleep(Duration::new(2, –));
    String::from("Hello, there from file 2")
}

The threaded listing shows where each independent read is spawned and where `join` waits for both threads to finish. section 10.2

The async version uses the Tokio runtime, `async fn`, `tokio::spawn`, `.await`, and `tokio::join!`. An async call must be awaited for its result; merely calling the async functions in spawned tasks does not run their bodies as intended. The demonstrated `sleep` calls block their threads, so they should not be mistaken for nonblocking I/O. section 10.2

How Rust Servers, Services, and Apps covers it

How deep it goes
Defines concurrency against parallelism, compares scheduling models, and works through sequential, threaded, and Tokio-based examples.
Examples
Compares two delayed file reads run sequentially, in operating-system threads, and in Tokio tasks.
What it assumes
Assumes familiarity with Rust functions and application code; treats the async deep dive as optional for web programming.
What you can do after
Practice/perform it by spawning and joining independent Rust threads, then trying Tokio tasks with explicit awaits.
How it connects
Connects multithreading and async I/O to HTTP request handling, application state, Tokio, futures, and parallelism.

Also explained in

Compare how 23 books explain concurrency →

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.