线程
你会学到什么
thread::spawn启动一个新线程,返回JoinHandle。join()等待线程结束并取回返回值。- 闭包要用
move把数据所有权交给线程。
最小示例
use std::thread;
let handle = thread::spawn(|| 1 + 2);
let result = handle.join().unwrap(); // 3
运行代码
cd examples
cargo run -p rt_25_threads
cargo test -p rt_25_threads
代码讲解
把数据 move 进每个线程,各算各的,最后 join 汇总:
let handles: Vec<_> = chunks
.into_iter()
.map(|chunk| thread::spawn(move || chunk.iter().sum::<i32>()))
.collect();
let total: i32 = handles.into_iter().map(|h| h.join().unwrap()).sum();
spawn 的闭包必须 'static(不借用栈上的临时数据),所以通常用 move 转移所有权。线程的返回值通过 join() 拿到,它返回 Result,因为线程可能 panic。
常见错误
借用了主线程的局部变量:
let data = vec![1, 2, 3];
thread::spawn(|| println!("{data:?}")); // ❌ 可能在 data 释放后才运行
加 move:thread::spawn(move || ...)。
练习
- 启动 3 个线程,各返回自己的编号,收集成
Vec。 - 测量串行求和与并行求和在大数据上的耗时差异。
小结
线程让任务真正并行。move 转移所有权满足 'static 约束,join 收回结果。
下一步
线程之间常用消息通信。下一章学习 channel。
完整示例代码
下面是 examples/25_threads/ 的完整源码。无需 clone 仓库,直接在页面上阅读、复制、对照运行。
examples/25_threads/src/main.rs
//! 用 thread::spawn 创建线程,用 join 收集结果。
use std::thread;
/// 把每个分片交给一个线程求和,最后汇总。
fn parallel_sum(chunks: Vec<Vec<i32>>) -> i32 {
let handles: Vec<_> = chunks
.into_iter()
.map(|chunk| thread::spawn(move || chunk.iter().sum::<i32>()))
.collect();
handles
.into_iter()
.map(|handle| handle.join().expect("线程 panic"))
.sum()
}
fn main() {
let chunks = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
println!("parallel sum = {}", parallel_sum(chunks));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sums_in_parallel() {
let chunks = vec![vec![1, 2, 3], vec![4, 5, 6]];
assert_eq!(parallel_sum(chunks), 21);
}
#[test]
fn handles_empty() {
assert_eq!(parallel_sum(vec![]), 0);
}
} examples/25_threads/Cargo.toml
[package]
name = "rt_25_threads"
version.workspace = true
edition.workspace = true
publish.workspace = true