为什么在此迭代中,数据被可变地借用了并行迭代器的结果?

时间:2018-08-07 22:54:59

标签: 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 | |     });
   | |_____^

我不明白如何可变地借用数据。

1 个答案:

答案 0 :(得分:1)

这是因为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);

什么是最适合您的呢?鉴于您与我们分享了一些小样本,我不能完全确定,但希望可以让您了解正在发生的事情。