
Rust利用所有权(Ownership)系统,在编译时保证线程安全,从根本上杜绝了数据竞争(Data Race);其多线程编程主要:
std::thread:用于创建和管理线程。std::sync::mpsc:消息传递(Message Passing),使用 Channel(通道)进行线程间的通信和同步。
线程std::thread
Rust 的标准库使用 1:1 线程模型,即一个 Rust 线程直接对应一个操作系统线程。
创建spawn
使用 thread::spawn 函数来创建一个新线程,其接收一个闭包作为线程执行体,返回 JoinHandle<T>(T 是闭包返回值类型)。
- join:等待线程执行完成;
- detach:分离线程(变为后台线程,由操作系统接管);在无需等待线程时使用;
使用thread::Builder可设置线程一些信息(线程名、栈大小等)。
若在新线程中使用主线程的变量,必须将这些变量的所有权转移(Move)给新线程。
rust
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let builder = thread::Builder::new()
.name("channel-test".to_string())
.stack_size(4 * 1024 * 1024);
// 必须使用 move 关键字,将 v 的所有权强制转移到闭包内
// let handle = thread::spawn(move || {
let handle = builder.spawn(move || {
println!("向量 v: {:?}", v);
thread::sleep(Duration::from_millis(10));
});
// 此时 v 在主线程中已不可用
// println!("{:?}", v); // 这一行如果取消注释会报错
handle.join().unwrap();
}
线程间通信Channel
线程间通信(IPC)是多线程协作的核心,Rust 基于 CSP(通信顺序进程) 模型提供了 mpsc 通道(Multiple Producer Single Consumer;多生产者、单消费者):
Sender<T>:发送端,可克隆(支持多生产者);通过send发送数据。Receiver<T>:接收端,不可克隆(单消费者)- 通过
recv/try_recv/recv_timeout接收数据。 Receiver实现了迭代器 trait,可直接遍历。
- 通过
mpsc::channel() 默认创建的是无界(unbounded)缓冲区通道,发送端 send 不会阻塞。数据通过 Channel 传递时,所有权会从 Sender 转移到 Receiver,天然避免数据竞争(无需手动同步)。
mpsc::sync_channel(n) 创建的则是带容量限制通道:
- 当通道内数据量达到容量
n时,send会阻塞,直到有数据被接收。 - 若容量为
0,则send必须等待recv调用(严格同步)
多生产者(克隆 Sender)示例
rust
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
pub fn run_mpsc_clone() {
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone(); // 克隆发送端,支持多线程发送
// 线程 1 发送
thread::spawn(move || {
let vals = vec![
String::from("消息1"),
String::from("消息2"),
String::from("消息3"),
];
for val in vals {
tx.send(format!("线程 1: {}",val)).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 线程 2 发送
thread::spawn(move || {
let vals = vec![
String::from("消息1"),
String::from("消息2"),
String::from("消息3"),
];
for val in vals {
tx1.send(format!("线程 2: {}",val)).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 接收所有消息(迭代器方式,直到所有 Sender 关闭)
for received in rx {
println!("收到: {}", received);
}
}
channel错误处理
send 和 recv 均返回 Result<T, SendError<T>>/Result<T, RecvError>,错误场景:
send失败:所有Receiver已被销毁(通道关闭)。recv失败:所有Sender已被销毁(无更多数据发送)。
多消费者
std::sync::mpsc 只提供单消费者。要实现多消费者:
- 使用
crossbeam-channelcrate(性能高且功能强大) - 使用
Arc<Mutex<Receiver>>包裹标准库的mpsc::Receiver(不推荐,因为锁会导致性能下降)。
crossbeam-channel实现的是竞争消费(Work Stealing/Load Balancing):一条消息只能被其中一个消费者抢到,而不是广播给所有人。
多消费者(receiver也可clone):
plain
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use crossbeam_channel::unbounded;
pub fn run_mpmc() {
// 创建一个无界通道。
// s: Sender, r: Receiver
let (s, r) = unbounded();
// --- 1. 创建多个消费者 (Consumers) ---
for i in 0..3 {
// 关键点:Receiver 可以直接 clone!
let r_clone = r.clone();
thread::spawn(move || {
// 像迭代器一样接收消息
for msg in r_clone {
println!("消费者 [{}] 抢到了任务: {}", i, msg);
// 模拟处理耗时,观察负载均衡效果
thread::sleep(Duration::from_millis(500));
}
});
}
// --- 2. 创建多个生产者 (Producers) ---
for i in 0..3 {
let s_clone = s.clone();
thread::spawn(move || {
for j in 1..=5 {
let msg = format!("P{}-任务{}", i, j);
s_clone.send(msg).unwrap();
thread::sleep(Duration::from_millis(200));
}
});
}
// 主线程等待一会儿观察结果
// 注意:crossbeam 的 Receiver 不会阻塞主线程退出,这里强行 sleep 演示
thread::sleep(Duration::from_secs(3));
println!("演示结束");
}
广播模式
crossbeam-channel一条消息只能被消费一次,以下三方库提供广播:
- Tokio (异步): 使用
tokio::sync::broadcast。 - 同步多线程: 使用
buscrate 或者postagecrate。
plain
use std::thread;
use bus::Bus;
pub fn run_bus() {
let mut bus = Bus::new(10); // 容量 10
// 创建两个接收者
let mut rx1 = bus.add_rx();
let mut rx2 = bus.add_rx();
thread::spawn(move || {
// recv 是阻塞的
println!("消费者 1 收到: {}", rx1.recv().unwrap());
});
thread::spawn(move || {
println!("消费者 2 收到: {}", rx2.recv().unwrap());
});
// 广播消息
bus.broadcast("bus-send message!".to_string());
thread::sleep(std::time::Duration::from_secs(1));
}