← 中文资源

简体中文版本

Rayon 并行映射

用 Rayon 并行映射切片,把顺序迭代变为工作窃取式并行计算。

阅读英文原文

功能说明

该示例用 Rayon 的并行迭代器把一个顺序的“映射并求和”变成多线程执行。par_iter 自动把工作切分到线程池,各线程以工作窃取平衡负载;结果与顺序版本完全一致,因此可并行化而不改变语义。另一个函数对可变切片就地并行转换,填充顺序由调用方保证。

关键代码

导入 prelude 后,切片获得 par_iter 与 par_iter_mut 等并行适配器,接口与顺序迭代器基本相同。求和用 saturating_mul 避免溢出恐慌,并把结果归约。就地转换用 for_each 写入每个槽位,checked_mul 在溢出时保留原值,避免未定义行为。测试用一千个数比较并行与顺序结果,确保并行化没有引入差异。

使用注意

并行化只在工作足够重、元素足够多时才划算:对极小的切片,线程调度与切分开销会超过收益。闭包必须是线程安全的,共享可变状态需用同步原语,否则编译期即会拒绝。工作窃取依赖任务粒度,粒度过粗会让某个线程成为瓶颈,可用 with_min_len 调整切分下限。并行不改变语义,但改变了执行顺序,含副作用的闭包必须自行保证可交换。

代码示例

use rayon::prelude::*;

/// Sum of squares, computed across all available worker threads.
pub fn sum_of_squares(values: &[i64]) -> i64 {
    values.par_iter().map(|value| value.saturating_mul(*value)).sum()
}

/// Transform each element in place, preserving order in the result.
pub fn transform(value: &mut [i64], factor: i64) {
    value.par_iter_mut().for_each(|slot| {
        *slot = slot.checked_mul(factor).unwrap_or(*slot);
    });
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn squares_match_sequential() {
        let data: Vec<i64> = (1..=1000).collect();
        let expected: i64 = data.iter().map(|v| v * v).sum();
        assert_eq!(sum_of_squares(&data), expected);
    }
}