Rust 中的并发与多线程:安全性与性能

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust中的并发与多线程:编写安全且快速的代码



现代程序很少以单线程模式运行。请求处理、文件操作、网络通信——所有这些都需要并行执行任务。Rust提供了一种独特的并发方法:它在编译阶段保证内存安全,防止数据竞争。在本文中,我们将探讨如何在Rust中使用线程、通道、互斥锁和异步编程。



1. 多线程基础:创建和管理线程



在Rust中,线程通过标准库std::thread创建。每个线程独立执行,但编译器会严格检查变量的生命周期。



创建线程

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

fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("线程: {}", i); thread::sleep(Duration::from_millis(100)); } });

for i in 1..5 { println!("主线程: {}", i); thread::sleep(Duration::from_millis(100)); }

handle.join().unwrap(); // 等待线程结束}


在闭包中捕获所有权

如果线程使用外部作用域的变量,需要通过move转移所有权:

let data = vec![1, 2, 3];

let handle = thread::spawn(move || { println!("数据: {:?}", data);});

handle.join().unwrap();// println!("{:?}", data); // 错误!data已被移动


2. 数据共享:互斥锁和锁



为了从多个线程安全地访问共享数据,Rust使用Mutex(互斥锁)与Arc(原子引用计数)结合。



Mutex和Arc示例

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!("结果: {}", *counter.lock().unwrap()); // 10}


重要提示: Mutex在离开作用域时会自动解锁。这可以在编译层面防止死锁(deadlock)。



RwLock——适用于频繁读取

如果数据很少修改但经常读取,请使用RwLock:

use std::sync::RwLock;

let lock = RwLock::new(5);

{ let r1 = lock.read().unwrap(); let r2 = lock.read().unwrap(); // 可以同时读取 println!("{} {}", r1, r2);}

{ let mut w = lock.write().unwrap(); *w += 1; // 写入操作会阻塞读取}


3. 通道:线程间消息传递



Rust通过通道(std::sync::mpsc)支持actor模型。这使得线程可以在没有共享内存的情况下交换数据。



通道示例

use std::sync::mpsc;use std::thread;

fn main() { let (tx, rx) = mpsc::channel();

thread::spawn(move || { let vals = vec!["hello", "from", "the", "thread"]; for val in vals { tx.send(val).unwrap(); thread::sleep(std::time::Duration::from_secs(1)); } });

for received in rx { println!("收到: {}", received); }}


多个发送者

通过mpsc::Sender可以克隆发送者以用于多个线程:

let (tx, rx) = mpsc::channel();let tx1 = tx.clone();

thread::spawn(move || { tx1.send("线程 1").unwrap(); });thread::spawn(move || { tx.send("

博客

书籍推荐