为了练习 Rust,我正在实施光线追踪器。
第一步我只使用球体来实现它。我会遍历一个 Vector of Sphere 结构。 我可以通过做
rayon
.使用
into_iter_par
轻松提高性能
现在我正在尝试添加立方体。所以我没有循环
Vec<Sphere>
,而是循环Vec<Box<dyn Body>>
。这似乎否定了使用人造丝获得的性能。
这种性能损失是如何发生的,我可以修复它吗?
在此代码片段中,我可以重现该行为。
use rayon::prelude::*;
use std::f64::consts::PI;
use std::time::Instant;
pub trait Body: Sync + Send {
fn size(&self) -> f64 {
0.
}
}
#[derive(Clone)]
pub struct Sphere {
radius: f64,
}
impl Sphere {
pub fn new() -> Self {
Sphere { radius: 4.0 }
}
}
impl Body for Sphere {
fn size(&self) -> f64 {
4.0 / 3.0 * PI * self.radius * self.radius * self.radius
}
}
pub struct World {
bodies: Vec<Box<dyn Body>>,
spheres: Vec<Sphere>,
}
impl World {
fn new() -> Self {
let mut world = World {
bodies: vec![],
spheres: vec![],
};
for _ in 0..100000000 {
world.spheres.push(Sphere::new());
world.bodies.push(Box::new(Sphere::new()));
}
world
}
}
pub fn main() {
println!("Creating structs");
let world = World::new();
println!("Normal,Spheres");
let timer = Instant::now();
world.spheres.iter().map(|s| s.size()).sum::<f64>();
println!("elapsed time:{:?}", timer.elapsed());
println!("Normal,Bodies");
let timer = Instant::now();
world.bodies.iter().map(|s| s.size()).sum::<f64>();
println!("elapsed time:{:?}", timer.elapsed());
println!("Parallel,Spheres");
let timer = Instant::now();
world.spheres.into_par_iter().map(|s| s.size()).sum::<f64>();
println!("elapsed time:{:?}", timer.elapsed());
println!("Parallel,Bodies");
let timer = Instant::now();
world.bodies.into_par_iter().map(|s| s.size()).sum::<f64>();
println!("elapsed time:{:?}", timer.elapsed());
}
使用发布版本运行时,会产生输出:
Creating structs
Normal,Spheres
elapsed time:97ns
Normal,Bodies
elapsed time:323.960404ms
Parallel,Spheres
elapsed time:88.960257ms
Parallel,Bodies
elapsed time:6.015788183s
你没有使用总和,所以第一个被完全优化掉了。你需要用它做一些事情,比如打印:
let sum = world.spheres.iter().map(|s| s.size()).sum::<f64>();
println!("elapsed time:{:?} ({sum})", timer.elapsed());
这个基准没有意义。
Box<dyn Body>
will 会更慢,但它允许您存储您不使用的不同对象。将其与存储枚举或将不同的对象类型存储在不同的Vec
s中进行比较。iter
的平行等价物是par_iter
。使用 into_par_iter
也会掉落物品,这可能比总和花费更多的时间。我提供的代码片段不是我实际的光线追踪器或基准。这是我尝试在一个片段中重现我的问题。
我在这里得到了答案https://github.com/rayon-rs/rayon/issues/1038
TL:DR 预计会放缓