Rayon线程池相交会导致性能开销



我有一个更大的程序,我可以总结如下:

SequentialPart
ThreadPoolParallelized
SequentialPart
ParallelPartInQuestion
SequentialPart

此代码被按顺序调用多次。

我正在使用Rayon线程来并行化第二部分,比如:

final_results = (0..num_txns).into_par_iter()
.filter_map(|idx| {
if !matches!(ret, None) {
return None;
}
match last_input_output.take_output(idx) {
ExecutionStatus::Success(t) => Some(t),
ExecutionStatus::SkipRest(t) => {
Some(t)
}
ExecutionStatus::Abort(err) => {
None
}
}
}).collect();

我已经使用并行块完成了这项工作

let interm_result: Vec<ExtrResult<E>> = (0..num_txns)
.collect::<Vec<TxnIndex>>()
.par_chunks(chunk_size)
.map(|chunk| {

不管怎样,我注意到,当这个代码第一次运行时,一切都如预期的那样工作,我从中获得了不错的性能提升

然而,在第二次迭代中,第一段并行代码(ThreadPoolParallelized(每次运行速度大约慢20%。

所以我得出的结论是,不知何故,Rayon必须留下一些东西,这些东西必须在之后清理掉,从而导致性能下降。

对此我能做点什么吗?

编辑:输出的作用是:

outputs: Vec<CachePadded<ArcSwapOption<TxnOutput<T, E>>>>, // txn_idx -> output.
pub fn take_output(&self, txn_idx: TxnIndex) -> ExecutionStatus<T, Error<E>> {
let owning_ptr = self.outputs[txn_idx]
.swap(None)
.expect("Output must be recorded after execution");
if let Ok(output) = Arc::try_unwrap(owning_ptr) {
output
} else {
unreachable!("Output should be uniquely owned after execution");
}
}

TLDR;如果您创建了一个自定义的人造丝线程池,同时还通过函数调用(如par_chunkspar_iter(使用全局线程池,那么一旦调用了自定义线程池,就需要清理全局线程池。

我发现了问题的原因。此执行中的第一个并行部分使用了手动创建的线程池。但是,如果未另行指定,into_par_iter将使用全局线程池,并使其保持活动状态一段时间。这会干扰手动创建的线程池

let interm_result: Vec<ExtrResult<E>> = RAYON_EXEC_POOL.install(|| {
(0..num_txns)

通过专门包装本应在pool.install调用中并行执行的代码,它重新使用了相同的线程池,不会创建一个以后必须销毁的额外线程池,并保留了性能。

最新更新