rust - 为什么在这个迭代中数据被可变地借用而不是并行迭代器的结果?
问题描述
我有下面的玩具示例,我在其中迭代一个简单的结构向量并对它们进行并行操作。在并行操作之后,我想将所有结果加载到一个稀疏矩阵中。
extern crate rayon;
extern crate sprs;
use rayon::prelude::*;
use sprs::TriMat;
pub struct Data {
i: usize,
}
fn eval<'a>(d: &Data) -> usize {
d.i * 2
}
fn main() {
let data = vec![1, 2, 3, 4];
let mut recs = Vec::new();
for x in data {
let s = Data { i: x };
recs.push(s);
}
let results = recs.par_iter().map(eval);
let mut matrix = TriMat::new((4, 2));
results.enumerate().for_each(|(j, scores)| {
matrix.add_triplet(j, j as usize, 1);
});
}
代码导致错误:
error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure
--> src/main.rs:26:9
|
26 | matrix.add_triplet(j, j as usize, 1);
| ^^^^^^
|
help: consider changing this closure to take self by mutable reference
--> src/main.rs:25:34
|
25 | results.enumerate().for_each(|(j, scores)| {
| __________________________________^
26 | | matrix.add_triplet(j, j as usize, 1);
27 | | });
| |_____^
我不明白数据是如何被可变地借用的。
解决方案
这是因为map
实际上并没有做任何事情......它创建了一个尚未迭代的新迭代器。
一旦我们点击matrix.add_triplet(j, j as usize, 1);
代码,那个迭代器就会被迭代,但是......它是一个ParallelIterator
......因此,Rust 编译器现在关心数据竞争。
我可以看到你有两个选择。
首先,您可以立即强制评估迭代器..:
let results: Vec<_> = recs.par_iter().map(eval).collect();
// ...
results.iter().enumerate() // ...
或者您可以将对矩阵的访问包装在Mutex
(或其他同步机制)中:
use std::sync::Mutex;
// ...
let mut matrix = Mutex::new(TriMat::new((4, 2)));
// ...
matrix.lock().unwrap().add_triplet(j, j as usize, 1);
鉴于您与我们分享的小样本,我不完全确定什么对您最好,但希望这能让您了解正在发生的事情。