我当时正在考虑使用Rayon的并行迭代器功能,但是我担心迭代小型集合的性能。
并行化开销有时可能会导致小型集合的运行速度变慢。如果我为多线程做必要的准备工作,则与使用单线程版本相比,迭代2个元素要慢。如果我有4000万个元素,那么并行将使我的线性性能得到改善。
我了解了ParallelIterator::weight
(0.6.0),但是我不知道我是否应该为小型藏品优化这种极端情况,或者人造丝很聪明并且可以在幕后处理所有事情。
if collection_is_small() {
// Run single threaded version...
} else {
// Use parallel iterator.
}
已处理元素的ParallelIterator::weight
为1。有关正确定义,请参阅相关文档,但是处理单个元素很便宜。
Google将我转到了旧的文档页面。从版本0.8.0开始,Weight
已过时,removed已弃用。
答案 0 :(得分: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创建一个全局线程池,并使用工作窃取来平衡线程之间的工作。线程池是每个进程的一次性设置成本,工作窃取有助于确保工作仅在需要时才跨越线程边界。这就是为什么上面有两个使用相同线程的输出的原因。
答案 1 :(得分:0)
不推荐使用重量API,而推荐使用split length control。 默认情况下,Rayon将在每个项目处拆分,从而有效地使所有计算并行进行,可以通过以下方式配置此行为 with_min_len。
设置希望在每个线程中处理的迭代器的最小长度。人造丝不会分裂得比这个长度小,但是当然迭代器开始时可能会更小。
诸如zip和interleave之类的生产者将使用两个最小值中的较大者。 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提供代码)