Rust 用 rayon 把串行迭代改成数据并行:几行代码吃掉多核性能
test12026-10-031 次阅读
并行就这么简单
rayon 是 Rust 生态里做数据并行的标杆库。它最大的特点是“几乎不改动你的代码形态”:把 iter() 换成 par_iter(),剩下的链式调用(map、filter、fold)原样保留,背后却自动调度到线程池、跑满所有核心。
从串行到并行
use rayon::prelude::*;
fn sum_of_squares(nums: &[u32]) -> u32 {
nums.par_iter() // 仅此一处从 .iter() 改为 .par_iter()
.map(|&x| x * x)
.sum()
}
对于纯计算、彼此无共享写的数据,这种改法几乎没有风险,因为 rayon 要求闭包满足 Send 加 Sync,编译器会替你把住并发安全的大门。
并行处理文件批量任务
假设要批量读取若干文件并统计行数,串行很容易成为瓶颈。
use std::fs;
use rayon::prelude::*;
fn count_lines_in_dir(paths: &[String]) -> usize {
paths.par_iter()
.map(|p| fs::read_to_string(p).map(|s| s.lines().count()).unwrap_or(0))
.sum()
}
用 fold 加 reduce 做有状态的聚合
并行下不能直接用可变累加器,rayon 用 fold 在每个线程本地聚合,再用 reduce 合并结果,既快又安全。
let total: usize = items.par_iter()
.fold(|| 0usize, |acc, it| acc + it.size())
.reduce(|| 0usize, |a, b| a + b);
什么时候用、什么时候别用
- 数据量大、每项计算偏重时收益明显;对极小集合,线程调度开销反而可能更慢,先测量再决定。
- 闭包里不要捕获可变全局状态,rayon 的 Send/Sync 约束会拒绝这类写法,这正是它安全的原因。
- I/O 密集任务优先用 async 运行时,rayon 擅长的是 CPU 密集的“把一份数据拆开算”。
- 用 RAYON_NUM_THREADS 可以限制线程数,避免在某些容器环境里吃满 CPU 影响同机其他服务。
一句话:遇到“对一堆东西做同样的计算”,先想想能不能 par_iter(),往往几行改动就换来近线性的加速。
T
test1
文章作者
并行就这么简单 rayon 是 Rust 生态里做数据并行的标杆库。它最大的特点是“几乎不改动你的代码形态”:把 it...
- 分类
- 技术
- 发布时间
- 2026-10-03
- 字数
- 约 1118 字
- 阅读
- 1 次
