使用Arc<Mutex<anyhow::Result<()>>>时Rust Rayon为何耗时更长?
为什么加锁后程序耗时暴增?
你的核心问题是Mutex的竞争直接让并行效率完全丧失:
- 你用
Arc<Mutex<Vec<_>>>让每个线程处理完文件后都去抢锁,再往Vec里push结果。但push本身是极快的操作,可抢锁的过程是串行的——每个线程都得等前一个线程释放锁才能执行,相当于把原本的并行任务硬生生拖成了串行执行,大部分时间都花在等待锁释放上,而非真正处理文件。 - 无锁版本(推测你是去掉了结果收集逻辑)没有锁的竞争,线程能真正并行处理任务,所以耗时极低。
正确的做法:用Rayon自带的结果收集机制
Rayon已经内置了高效的并行结果收集能力,完全不需要手动加Mutex。把for_each换成map,再用collect直接得到结果Vec,全程无锁,性能和无锁版本一致:
fn main() -> anyhow::Result<()> { let (files, _) = utils::get_files_from_folder(input_folder)?; // Rayon自动处理并行结果的收集,无需手动加锁 let results: Vec<anyhow::Result<()>> = files.par_iter().map(|path| { if let Some(extension) = path.extension() { if extension == "txt" { redact::redact_txt_and_write_json(path, ®ex_vec, &output_folder) } else { eprintln!( "{}INVALID EXTENSION: {} - Not yet implemented", *RED_ERROR_STRING, extension.to_string_lossy(), ); // 并行任务里别直接exit,返回错误更合理 Err(anyhow::anyhow!("invalid extension: {}", extension.to_string_lossy())) } } else { eprintln!("{}EXTENSION not found", *RED_ERROR_STRING); Err(anyhow::anyhow!("extension not found for path: {}", path.display())) } }).collect(); println!("{:?}", results); Ok(()) }
额外优化点
- 别在并行任务里直接
std::process::exit(1):多线程运行时,任意线程调用exit会直接终止整个程序,可能导致其他线程的任务半途而废,换成返回错误统一处理更稳妥。 - 把
par_iter_mut改成par_iter:你的代码里并没有修改path,用不可变迭代器更安全,也能避免不必要的可变借用开销。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

