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

结合场景再看三个关注点

  1. join 处理线程 panicResult
  2. 闭包若捕获栈上数据需 move 或保证寿命
  3. 线程不是 async 任务,更重

核心概念与准确模型

  • spawnJoinHandle<T>
  • join 等待并取 Result<T>
  • 线程局部:thread_local!
  • Builder 可命名/设栈大小

与 channel/Mutex 组合才构成完整并发。

设计动机

  • 安全地暴露 OS 线程
  • 通过 Send 防数据竞争
  • 显式 join 表达生命周期

边界与误区

  • 无界创建线程可耗尽资源 → 线程池
  • 忘记 join 可能导致主线程先退出
  • 在 async 运行时里阻塞线程要谨慎

[!warning] 常见误区:在 async 函数里 thread::sleep 当并发 会阻塞工作线程;async 用定时器 future。

工程实践

  1. CPU 密集可考虑线程池
  2. I/O 密集优先 async 生态
  3. 命名线程便于排障
  4. 传播错误:join 后处理 panic 或返回值

本节总结

  • spawn/join 基础
  • move + Send
  • 与 channel/锁组合

自测题

  1. 为什么 spawn 的闭包常常要 move
  2. join 返回 Err 通常表示?
参考答案
  1. 保证闭包不借用短命栈数据。
  2. 子线程 panic。

延伸阅读与资料来源

资料类型支撑内容
The Book — Fearless Concurrency官方书并发
std::thread标准库线程 API
创建于 2026/7/15 更新于 2026/7/15