简体   繁体   English

如何避免 IntoParallelIterator 绑定的可变和不可变借用

[英]How to avoid mutable and immutable borrow with IntoParallelIterator bound

I have a function that operates on a Vec<T> which purpose is to extend the vector with new items generated using reference to existing items.我有一个 function ,它在Vec<T>上运行,其目的是使用引用现有项目生成的新项目来扩展向量。 I'm trying to run the generation of new data in parallel using rayon .我正在尝试使用rayon并行运行新数据的生成。

This is a minimal example:这是一个最小的例子:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
    let mut foo = Foo {
        data: (0..1000).into_iter().collect(),
    };
    foo.run();
}

struct Foo<T> {
    data: Vec<T>,
}

type Pair<'a, T> = (&'a T, &'a T);

impl<'a, T: Clone + 'a> Foo<T>
where
    Vec<Pair<'a, T>>: IntoParallelIterator<Item = Pair<'a, T>>,
    [T; 2]: IntoParallelIterator,
    Vec<T>: FromParallelIterator<<[T; 2] as IntoParallelIterator>::Item>,
{
    fn run(&'a mut self) {
        let combinations: Vec<Pair<'a, T>> = self
            .data
            .iter()
            .combinations(2)
            .map(|x| (x[0], x[1]))
            .collect();

        let mut new_combinations: Vec<T> = combinations
            .into_par_iter()
            .flat_map(|(a, b)| bar(a, b))
            .collect();

        self.data.append(&mut new_combinations);
    }
}


fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
    [a.clone(), b.clone()]
}

You can find a link to Playground here .您可以在此处找到 Playground 的链接。

Building the above example raises this error:构建上述示例会引发此错误:

error[E0502]: cannot borrow `self.data` as mutable because it is also borrowed as immutable
  --> src/main.rs:36:9
   |
17 |   impl<'a, T: Clone + 'a> Foo<T>
   |        -- lifetime `'a` defined here
...
24 |           let combinations: Vec<Pair<'a, T>> = self
   |  ___________________________----------------___-
   | |                           |
   | |                           type annotation requires that `self.data` is borrowed for `'a`
25 | |             .data
26 | |             .iter()
   | |___________________- immutable borrow occurs here
...
36 |           self.data.append(&mut new_combinations);
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

As far as I understand since I am collecting into a let new_combinations: Vec<T> there should be no immutable references to self.data and I should be able in theory to borrow it mutably to append the new combinations.据我了解,因为我收集到let new_combinations: Vec<T>不应该有对self.data的不可变引用,理论上我应该能够将它可变地借给 append 新组合。 However, it seems that self.data is borrowed for 'a which extends beyond the scope of this method.但是,似乎self.data是为'a借用的,它超出了此方法的 scope。 I cannot find a way to avoid specifying the lifetime fn run(&'a mut self) since I need to specify that the lifetimes of the references to the items of self.data cannot outlive self when creating the combinations.我找不到避免指定生命周期fn run(&'a mut self)的方法,因为我需要指定在创建组合时对self.data项的引用的生命周期不能超过self

Is there a way to allow this method to operate as expected, that is: 1) select a list of references to the items in self.data , 2) apply a function that creates new items T in parallel and finally 3) update self.data with the new items.有没有办法让这种方法按预期运行,即:1)select 对self.data中项目的引用列表,2)应用 function 并行创建新项目T ,最后 3)更新self.data新项目的self.data

Note that as a workaround one could return the new_combinations from the method and append them to self.data separately.请注意,作为一种解决方法,可以将方法中的new_combinations和 append 分别返回给self.data

Would be great if all of this would be possible by avoiding as many collect() as possible while operating directly with iterators only.如果所有这一切都可以通过避免尽可能多的collect()而直接使用迭代器操作,那就太好了。

The elements in new_combinations are cloned and therefore don't borrow from combinations any more. new_combinations中的元素被克隆,因此不再从combinations中借用。 Your annotations, however, state that T: 'a , meaning Rust has to treat them as still borrowed.但是,您的注释 state 表示T: 'a ,这意味着 Rust 必须将它们视为仍然借来的。

I personally think you are being way too excessive with the lifetimes annotations here, you could remove almost all of them.我个人认为你对这里的生命周期注释太过分了,你可以删除几乎所有的注释。 The compiler is very good in figuring them out automatically in most situations.在大多数情况下,编译器非常擅长自动找出它们。

Further, your trait restrictions were sadly mislead by the compiler hints.此外,可悲的是,编译器提示误导了您的特征限制。 They are all automatically fulfilled once you specify T: Clone + Send + Sync .一旦您指定T: Clone + Send + Sync ,它们都会自动完成。

Here you go:这里是 go:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
    let mut foo = Foo {
        data: (0..10).collect(),
    };
    foo.run();
    println!("{:?}", foo.data);
}

struct Foo<T> {
    data: Vec<T>,
}

type Pair<'a, T> = (&'a T, &'a T);

impl<T: Clone + Send + Sync> Foo<T> {
    fn run(&mut self) {
        let combinations: Vec<Pair<T>> = self
            .data
            .iter()
            .combinations(2)
            .map(|x| (x[0], x[1]))
            .collect();

        let mut new_combinations: Vec<T> = combinations
            .into_par_iter()
            .flat_map(|(a, b)| bar(a, b))
            .collect();

        self.data.append(&mut new_combinations);
    }
}

fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
    [a.clone(), b.clone()]
}
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 2, 3, 2, 4, 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 6, 7, 6, 8, 6, 9, 7, 8, 7, 9, 8, 9]

Further, there is really no need for the Pair type:此外,确实不需要Pair类型:

use itertools::Itertools;
use rayon::prelude::*;

fn main() {
    let mut foo = Foo {
        data: (0..10).collect(),
    };
    foo.run();
    println!("{:?}", foo.data);
}

struct Foo<T> {
    data: Vec<T>,
}

impl<T: Clone + Send + Sync> Foo<T> {
    fn run(&mut self) {
        let combinations: Vec<_> = self
            .data
            .iter()
            .combinations(2)
            .map(|x| (x[0], x[1]))
            .collect();

        let mut new_combinations: Vec<T> = combinations
            .into_par_iter()
            .flat_map(|(a, b)| bar(a, b))
            .collect();

        self.data.append(&mut new_combinations);
    }
}

fn bar<T: Clone>(a: &T, b: &T) -> [T; 2] {
    [a.clone(), b.clone()]
}

About the last part of your question, the request to remove all .collect() calls if possible:关于您问题的最后一部分,如果可能,请求删除所有.collect()调用:

Sadly, I don't think you will be able to remove any of the collect() s.可悲的是,我认为您将无法删除任何collect() At least not with your current code layout.至少不是您当前的代码布局。 You definitely need to collect() between combinations() and into_par_iter() , and you also definitely need to collect() before append , because you need to release all references to self.data before you write into it.您肯定需要在 combine( combinations()into_par_iter() collect() () ,并且您还肯定需要在append之前collect() ,因为您需要在写入之前释放对self.data的所有引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM