Rust 并发编程

简介

本教程旨在深入探讨 Rust 语言的并发编程特性。我们将学习如何使用多个线程来提高应用程序的性能,以及如何处理共享状态和数据竞争等问题。

环境准备

基础知识

什么是并发?

并发指的是同时处理多个任务的能力。它与并行不同,后者是在同一时刻执行多个操作。Rust 提供了丰富的并发支持,可以让我们编写高效、安全的多线程应用程序。

什么是线程?

线程是一个轻量级的进程,它在同一进程内共享相同的内存空间。每个线程都可以独立地执行代码,使得多任务处理成为可能。

Rust 中的并发编程

创建一个新线程

Rust 标准库提供了 std::thread 模块来支持多线程编程。下面是如何创建和执行一个新线程的示例:

use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

等待线程完成

如果我们想要在主线程中等待新线程的执行结束,可以使用 join 方法:

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
        }
    });

    handle.join().unwrap();

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
    }
}

使用 move 关键字移动所有权

如果我们想要在新线程中使用主线程的数据,需要使用 move 关键字将所有权转移到新线程:

use std::thread;

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

    let handle = thread::spawn(move || {
        println!("Here's a vector: {:?}", v);
    });

    handle.join().unwrap();
}

共享状态和数据竞争

Mutex

互斥锁(Mutual Exclusion, Mutex)是一种同步原语,它可以保证在任意时刻只有一个线程能够访问某个资源。Rust 标准库提供了 std::sync::Mutex 类型来实现互斥锁:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

RwLock

读写锁(Read Write Lock, RwLock)允许多个线程同时读取数据,但只有一个线程能够写入数据。这种机制可以提高并发性能:

use std::sync::{Arc, RwLock};
use std::thread;

fn main() {
    let data = Arc::new(RwLock::new(vec![1, 2, 3]));
    let mut handles = vec![];

    for _ in 0..5 {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            println!("Read: {:?}", *data.read().unwrap());
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    let mut data = data.write().unwrap();
    data.push(4);
}

结论

本教程介绍了 Rust 中的并发编程基础知识,包括线程创建、等待、数据移动和共享状态管理。通过掌握这些技能,我们可以编写出高效、安全的多线程应用程序。