为什么人造丝不需要Arc<_>?



在 Programming Rust 的第 465 页上,您可以找到代码和解释(强调由我添加(

use std::sync::Arc;
fn process_files_in_parallel(filenames: Vec<String>,
glossary: Arc<GigabyteMap>)
-> io::Result<()>
{
...
for worklist in worklists {
// This call to .clone() only clones the Arc and bumps the
// reference count. It does not clone the GigabyteMap.
let glossary_for_child = glossary.clone();
thread_handles.push(
spawn(move || process_files(worklist, &glossary_for_child))
);
}
...
}

我们更改了词汇表的类型:要并行运行分析,调用方必须通过执行Arc::new(giga_map)传入Arc<GigabyteMap>,即指向已移动到堆中的GigabyteMap的智能指针。当我们调用 glossary.clone(( 时,我们正在复制Arc智能指针,而不是整个GigabyteMap。这相当于递增引用计数。通过此更改,程序将编译并运行,因为它不再依赖于引用生存期。只要任何线程拥有Arc<GigabyteMap>,它就会保持映射的活力,即使父线程提前退出。不会有任何数据争用,因为Arc中的数据是不可变的。

在下一节中,他们展示了用人造丝重写的内容,

extern crate rayon;
use rayon::prelude::*;
fn process_files_in_parallel(filenames: Vec<String>, glossary: &GigabyteMap)
-> io::Result<()>
{
filenames.par_iter()
.map(|filename| process_file(filename, glossary))
.reduce_with(|r1, r2| {
if r1.is_err() { r1 } else { r2 }
})
.unwrap_or(Ok(()))
}

您可以在重写为使用 Rayon 的部分中看到它接受&GigabyteMap而不是Arc<GigabyteMap>。不过,他们没有解释这是如何工作的。为什么人造丝不需要Arc<GigabyteMap>?人造丝如何摆脱接受直接参考?

Rayon 可以保证迭代器不会超过当前堆栈帧,这与我在第一个代码示例中假设thread::spawn不同。具体来说,引擎盖下的par_iter使用类似于 Rayon 的scope函数,它允许生成一个"附加"到堆栈的工作单元,并在堆栈结束之前加入。

因为 Rayon 可以保证(通过生命周期边界,从用户的角度来看(在函数调用par_iter退出之前连接任务/线程,所以它可以提供这个比标准库thread::spawn更符合人体工程学的 API。

Rayon 在scope函数的文档中对此进行了扩展。

相关内容

  • 没有找到相关文章

最新更新