Rayon会避免为少量工作产生线程吗?

问题描述 投票:2回答:2

我正在考虑使用Rayon的并行迭代器功能,但我担心迭代小集合的性能。

并行性开销有时会导致小型集合的减速。如果我为多线程做必要的准备,那么迭代超过2个元素比使用单线程版本要慢。如果我有4000万个元素,并行性将给我一个线性的性能提升。

我读到了关于ParallelIterator::weight (0.6.0)的内容,但是我不明白我是否应该为小型收藏品优化这种转角情况,或者如果Rayon是聪明的并处理引擎盖下的所有内容。

if collection_is_small() {
    // Run single threaded version... 
} else {
    // Use parallel iterator.
}

已处理元素的ParallelIterator::weight为1.有关良好定义的信息,请参阅相关文档,但处理单个元素的成本很低。

谷歌发给我一个旧的文档页面。从版本0.8.0开始,Weight被弃用并且removed

multithreading rust rayon
2个回答
1
投票

你可以凭经验看到这种行为不能得到保证:

use rayon::prelude::*; // 1.0.3

use std::thread;

fn main() {
    let ids: Vec<_> = (0..2)
        .into_par_iter()
        .map(|_| thread::current().id())
        .collect();
    println!("{:?}", ids);
}

该程序的各种运行显示:

[ThreadId(1), ThreadId(2)]
[ThreadId(1), ThreadId(1)]
[ThreadId(2), ThreadId(1)]
[ThreadId(2), ThreadId(2)]

话虽这么说,你应该执行自己的基准测试。默认情况下,Rayon创建一个全局线程池并使用工作窃取来平衡线程之间的工作。线程池是每个进程的一次性设置成本,并且工作窃取有助于确保工作仅在需要时跨越线程边界。这就是为什么上面的输出都使用相同的线程。


0
投票

权重API已被弃用,有利于split length control。默认情况下,Rayon将在每个项目上进行拆分,有效地使所有计算并行,这种行为可以通过with_min_len进行配置。

设置在每个线程中处理所需的最小迭代器长度。人造丝不会分裂任何小于这个长度,但当然迭代器可能已经开始变小了。

拉链和交错等生产商将使用两个最小值中的较大者。 flat_map中的链式迭代器和迭代器可以各自使用它们自己的最小长度。

extern crate rayon; // 1.0.3
use rayon::prelude::*;
use std::thread;

fn main() {
    println!("Main thread: {:?}", thread::current().id());
    let ids: Vec<_> = (0..4)
        .into_par_iter()
        .with_min_len(4)
        .map(|_| thread::current().id())
        .collect();
    println!("Iterations: {:?}", ids);
}

输出:

Main thread: ThreadId(0)
Iterations: [ThreadId(0), ThreadId(0), ThreadId(0), ThreadId(0)]

Playground(感谢@shepmaster代码)

© www.soinside.com 2019 - 2024. All rights reserved.