首页 > 解决方案 > 为什么在这个迭代中数据被可变地借用而不是并行迭代器的结果?

问题描述

我有下面的玩具示例,我在其中迭代一个简单的结构向量并对它们进行并行操作。在并行操作之后,我想将所有结果加载到一个稀疏矩阵中。

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

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

标签: rust

解决方案


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

鉴于您与我们分享的小样本,我不完全确定什么对您最好,但希望这能让您了解正在发生的事情。


推荐阅读