Rust 并发模式概览
常见并发结构:扇入扇出、工作池、背压、超时与防泄漏;线程与 async 的选择。
#synthesis
#growing
#dev
#rust
[!info] related notes
Rust 并发模式概览
这个概念为什么出现
会用 spawn/channel 之后,工程失败常在结构:任务泄漏、无界队列、无超时、关闭无协议。
本篇解释任务、队列、背压与关闭如何协作,不替代 并发 MOC 的阅读导航,也不绑定单一 crate 版本。
[!abstract] 一句话理解 用清晰的任务生命周期、有界队列背压、超时与统一取消,把线程/async 原语组装成可运维的并发系统。
最小可运行示例
场景:有界任务队列防止内存打爆
生产者提交任务,消费者处理;有界 channel 在队列满时阻塞生产者(背压)。
use std::sync::mpsc::sync_channel;
use std::thread;
// 业务意图:有界队列保护内存。
// 教学点:sync_channel 背压;丢弃发送端后让消费者排空并退出。
fn main() {
let (tx, rx) = sync_channel::<u32>(2);
let worker = thread::spawn(move || {
while let Ok(job) = rx.recv() {
println!("process job={job}");
}
});
for job in 1..=4 {
println!("submit {job}");
tx.send(job).unwrap();
}
drop(tx);
worker.join().unwrap();
}
建议运行:cargo run(可见 submit 与 process 交织,队列容量为 2)。
结合场景再看三个关注点
- 有界 = 背压
- 关闭协议:drop sender
- 真实系统还要超时与指标
核心模式地图
| 模式 | 要点 |
|---|---|
| 扇出 | 一任务变多任务并行 |
| 扇入 | 多结果汇聚 |
| 工作池 | 限制并发度 |
| 背压 | 有界队列/拒绝策略 |
| 超时 | 限制等待预算;不保证后台工作自动停止 |
| 取消 | 信号 + 任务协作检查 + 收尾;不是强制回滚 |
| 监督 | 任务失败重启策略 |
一次任务流应明确:接收任务 → 通过有界入口限制积压 → worker 消费 → 停止接收 → 丢弃发送端并排空或取消 → join 确认退出。示例只展示排空关闭;submit 日志在 send 之前,打印不代表提交已完成。
队列容量 2 限制的是缓冲消息数;正在处理的任务、阻塞生产者持有的数据与每条消息字节数仍占内存。若生产者本身无限 spawn,有界队列也不能给系统总资源设上限。
设计动机
- 把正确性从“能跑”提升到“可长期运行”
- 明确资源上限
- 对齐运维语义(耗尽、降级)
边界与误区
- 无界 buffer “先这样” → OOM
- fire-and-forget spawn 无 join/追踪
- 混用阻塞与 async 无隔离
[!warning] 常见误区:用 sleep 假装同步协调 用条件变量/channel/通知原语。
工程实践
- 先画数据流与所有权
- 每个 spawn 有人负责生命周期
- 超时+指标默认带上
- 压测验证背压
本节总结
- 模式 > 单 API
- 背压与关闭是一等公民
- 线程/async 按负载选择
自测题
- 无界 channel 的主要风险?
- 工作池解决什么问题?
参考答案
- 内存与延迟失控。
- 限制并发,稳定资源使用。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Concurrency | 官方书 | 基础 |
| Async Book | 社区书 | async 模式 |
| Tokio concepts | 生态 | 任务与 I/O |