Skip to content
Go back

Rust Concurrency in Practice

Fourth article in the Rust series: Explore Rust's concurrency capabilities, including threads, message passing, shared state, and the async/await asynchronous programming model.

Rust’s Concurrency Safety Guarantee

Rust has a famous motto: “Fearless Concurrency”. Thanks to the ownership system and type system, Rust can eliminate the vast majority of concurrency errors at compile time, such as data races.

Thread Basics

Creating Threads

Using move Closures

When you need to transfer data ownership between threads:

use std::thread;

fn main() {
    let data = vec![1, 2, 3, 4, 5];

    let handle = thread::spawn(move || {
        let sum: i32 = data.iter().sum();
        println!("Data sum: {}", sum);
        sum
    });

    // data has been moved, cannot be used here anymore
    let result = handle.join().unwrap();
    println!("Thread returned: {}", result);
}
rust

Message Passing

Rust’s standard library provides mpsc (multiple producers, single consumer) channels for inter-thread communication:

Shared State

Mutex (Mutual Exclusion Lock)

RwLock (Read-Write Lock)

When reads far outnumber writes, RwLock is more efficient than Mutex:

Async/Await Asynchronous Programming

For I/O-bound tasks, Rust’s async/await model is more efficient than threads:

Basic Async Functions

use tokio; // Most commonly used async runtime

async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

#[tokio::main]
async fn main() {
    match fetch_data("https://api.example.com/data").await {
        Ok(data) => println!("Fetched data: {} bytes", data.len()),
        Err(e) => eprintln!("Request failed: {}", e),
    }
}
rust

Concurrent Execution of Multiple Tasks

Using Stream for Async Data Streams

use tokio_stream::StreamExt;

async fn process_stream() {
    let mut stream = tokio_stream::iter(vec![1, 2, 3, 4, 5])
        .map(|x| x * 2)
        .filter(|x| *x > 4);

    while let Some(value) = stream.next().await {
        println!("Stream data: {}", value);
    }
}
rust

Practical Example: Concurrent Web Crawler

Here’s a simple crawler example that combines concurrency concepts:

Send and Sync Traits

Rust’s concurrency safety is ensured by two marker traits:

Most types automatically implement these traits. If you use types that don’t satisfy these constraints (like Rc<T>), the compiler will error at compile time, preventing you from writing code with data races.

Summary

Rust’s concurrency model is one of its most powerful features. Whether you use threads, message passing, or async programming, the compiler guards your code’s safety in the background. This is the true meaning of “fearless concurrency”—you can confidently write concurrent code because the compiler has already eliminated most hazards for you.

Previous: Rust Error Handling Best Practices

Congratulations on completing the “Learning Rust from Scratch” series! You’ve now mastered Rust’s four core concepts. Keep practicing, build more projects, and you’ll increasingly appreciate Rust’s charm.



Previous Post
Rust Error Handling Best Practices

评论区

文明评论,共建和谐社区