Channel 消息传递
问题
Rust 中如何使用 Channel 进行线程间通信?有哪些 Channel 实现?
答案
标准库 mpsc
use std::sync::mpsc;
use std::thread;
fn main() {
// 创建无界通道
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
tx.send("world").unwrap();
});
// 接收
println!("{}", rx.recv().unwrap()); // "hello"
println!("{}", rx.recv().unwrap()); // "world"
// rx.recv() → Err(发送端已 drop)
}
多生产者:
let (tx, rx) = mpsc::channel();
for i in 0..5 {
let tx = tx.clone();
thread::spawn(move || {
tx.send(format!("线程 {} 发送", i)).unwrap();
});
}
drop(tx); // 释放原始发送端
for msg in rx { // 迭代接收直到所有发送端关闭
println!("{}", msg);
}
有界通道
let (tx, rx) = mpsc::sync_channel(3); // 容量 3
// 当通道满时,send 会阻塞
tx.send(1).unwrap();
tx.send(2).unwrap();
tx.send(3).unwrap();
// tx.send(4) → 阻塞,直到 rx 接收
crossbeam Channel(推荐)
crossbeam 提供更强大的 Channel 实现:
use crossbeam::channel;
// 有界通道
let (tx, rx) = channel::bounded(10);
// 无界通道
let (tx, rx) = channel::unbounded();
// select! 多通道选择
use crossbeam::channel::select;
let (tx1, rx1) = channel::unbounded();
let (tx2, rx2) = channel::unbounded();
select! {
recv(rx1) -> msg => println!("从 rx1 收到: {:?}", msg),
recv(rx2) -> msg => println!("从 rx2 收到: {:?}", msg),
default(Duration::from_secs(1)) => println!("超时"),
}
通道类型对比
| 特性 | mpsc::channel | mpsc::sync_channel | crossbeam::channel |
|---|---|---|---|
| 有界/无界 | 无界 | 有界 | 两者都有 |
| 多生产者 | ✅ | ✅ | ✅ |
| 多消费者 | ❌ | ❌ | ✅(mpmc) |
| select | ❌ | ❌ | ✅ |
| 性能 | 一般 | 一般 | 优秀 |
常见面试问题
Q1: 什么时候用 Channel,什么时候用 Mutex?
答案:
- Channel:任务之间传递数据、生产者-消费者模式、流水线处理
- Mutex:多个线程需要原地修改共享数据结构
Go 的哲学:"用通信来共享内存"。Rust 两种方式都支持,根据场景选择。
Q2: mpsc 中 "mpsc" 是什么意思?
答案:
Multi-Producer, Single-Consumer。标准库只支持多个发送者对应一个接收者。如果需要多消费者(mpmc),使用 crossbeam-channel。
Q3: Channel 的 send 会失败吗?
答案:
会。当所有接收端已被 drop 时,send() 返回 Err(SendError)。同理,当所有发送端已被 drop 时,recv() 返回 Err(RecvError)。