在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<GigabyteMap>
a 的智能指针,方法是。当我们调用glossary.clone() 时,我们正在制作智能指针的副本,而不是整个. 这相当于增加引用计数。通过此更改,程序可以编译并运行,因为它不再依赖于引用生命周期。只要任何线程拥有一个,它就会使地图保持活动状态,即使父线程提前退出。不会有任何数据竞争,因为 an 中的数据是不可变的。GigabyteMap
Arc::new(giga_map)
Arc
GigabyteMap
Arc<GigabyteMap>
Arc
在下一节中,他们展示了用 Rayon 重写的内容,
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 是如何接受直接推荐的?