Rust 线程
std::thread 启动线程、move 闭包转移所有权、JoinHandle 等待与线程间基本协作入口。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust 线程
这个概念为什么出现
CPU 密集或需要并行的工作会用到 OS 线程。
Rust 标准库提供 std::thread,并把“什么能跨线程移动”交给类型系统(Send)。
[!abstract] 一句话理解
thread::spawn启动线程执行move闭包;通过JoinHandle等待结果;跨线程移动的数据必须满足Send。
最小可运行示例
场景:报表服务并行汇总两个分区计数
夜间任务把两个分区的行数并行统计,主线程 join 后相加。
use std::thread;
// 业务意图:并行统计两个分区的记录数。
// 教学点:spawn + move;join 取回结果;主线程汇总。
fn count_partition(name: &str, rows: u64) -> u64 {
println!("counting {name}");
rows // 示意
}
fn main() {
let h1 = thread::spawn(|| count_partition("p1", 120));
let h2 = thread::spawn(|| count_partition("p2", 80));
let total = h1.join().unwrap() + h2.join().unwrap();
println!("total_rows={total}");
}
建议运行:cargo run
期望输出(顺序可能交错):
counting p1
counting p2
total_rows=200
结合场景再看三个关注点
- join 处理线程 panic(
Result) - 闭包若捕获栈上数据需 move 或保证寿命
- 线程不是 async 任务,更重
核心概念与准确模型
spawn→JoinHandle<T>join等待并取Result<T>- 线程局部:
thread_local! - Builder 可命名/设栈大小
与 channel/Mutex 组合才构成完整并发。
设计动机
- 安全地暴露 OS 线程
- 通过 Send 防数据竞争
- 显式 join 表达生命周期
边界与误区
- 无界创建线程可耗尽资源 → 线程池
- 忘记 join 可能导致主线程先退出
- 在 async 运行时里阻塞线程要谨慎
[!warning] 常见误区:在 async 函数里 thread::sleep 当并发 会阻塞工作线程;async 用定时器 future。
工程实践
- CPU 密集可考虑线程池
- I/O 密集优先 async 生态
- 命名线程便于排障
- 传播错误:join 后处理 panic 或返回值
本节总结
- spawn/join 基础
- move + Send
- 与 channel/锁组合
自测题
- 为什么 spawn 的闭包常常要
move? join返回Err通常表示?
参考答案
- 保证闭包不借用短命栈数据。
- 子线程 panic。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Fearless Concurrency | 官方书 | 并发 |
| std::thread | 标准库 | 线程 API |