如何在Rust中为不同的线程克隆随机数生成器



我正在研究基于C++代码库(PBRT,如果有人熟悉的话(的光线跟踪器的Rust实现。C++版本定义的类之一是一系列采样器,以减少渲染图像中的噪声。在渲染过程中,只要需要随机数,就会将此采样器克隆到每个渲染线程中。这就是我在Rust中选择的方式,我承认这有点复杂:

#[derive(Clone)]
pub struct PixelSampler {
samples_1d: Vec<Vec<f64>>,
samples_2d: Vec<Vec<Point2<f64>>>,
current_1d_dimension: i32,
current_2d_dimension: i32,
rng: rngs::ThreadRng
}
pub enum Samplers {
StratifiedSampler {x_samples: i64, y_samples: i64, jitter_samples: bool, pixel: PixelSampler },
ZeroTwoSequenceSampler { pixel: PixelSampler }
}
impl Clone for Samplers {
fn clone(&self) -> Self {
match self {
Samplers::StratifiedSampler { x_samples, y_samples, jitter_samples, pixel } => { 
Samplers::StratifiedSampler {x_samples: *x_samples,
y_samples: *y_samples,
jitter_samples: *jitter_samples,
pixel: pixel.clone() }
}
Samplers::ZeroTwoSequenceSampler { pixel } => { Samplers::ZeroTwoSequenceSampler{ pixel: pixel.clone() } }
}
}
}

然后我还有一个Integrator,它有一个Samplers变域。在我的主渲染循环中,我为每个线程运行以下循环:

for _ in 0..NUM_THREADS {
let int_clone = integrator.clone(); // integrator just contains a Samplers
thread_vec.push(thread::spawn(move || {
loop {
// do main rendering loop
}
}));
}

但当我用这个编译时,我会得到错误:

"特征CCD_ 3不被实现用于CCD_;。

我的理解是,因为我只将克隆的版本移动到线程中,所以不需要实现Send。我做错了什么?

正如thread_rng()文档所说,它是:

[…]本质上只是对线程本地内存中PRNG的引用。

因此,通过克隆;rng";您没有复制生成器及其状态(我认为这是您的意图(,而是为线程本地RNG创建了一个新的句柄。该句柄有意不是Send,因为它访问线程本地RNG而不锁定以提高效率。

如果您希望结构包含实际的RNG,并克隆结构以复制它,则可以使用StdRng类型,这是推荐的、高效且安全的RNG。要实例化它,请使用SeedableRng特性中的方法。例如:

#[derive(Clone)]
pub struct PixelSampler {
samples_1d: Vec<Vec<f64>>,
samples_2d: Vec<Vec<Point2<f64>>>,
current_1d_dimension: i32,
current_2d_dimension: i32,
rng: StdRng,
}
// ...
let sampler = Samplers::ZeroTwoSequenceSampler {
pixel: PixelSampler {
samples_1d: vec![],
samples_2d: vec![],
current_1d_dimension: 0,
current_2d_dimension: 0,
rng: SeedableRng::from_entropy(),
},
};
// compiles because StdRng is Send
std::thread::spawn(move || sampler).join().unwrap();

操场上的榜样。

最新更新