当使用rayon并行迭代器时,同步和发送特质是什么?

3

我有一个特质的集合,我想为映射中的每个项目调用特质的可变方法。

目前我是顺序执行,并且我的集合如下所示:

use std::cell::RefCell;
use std::collections::*;
use std::rc::Rc;

trait Trait {
    fn foo_mut(&mut self);
}

fn main() {
    let mut items: HashMap<i32, Rc<RefCell<dyn Trait>>> = HashMap::new();
    // I have a separate data structure that holds Week<RefCell<dyn Trait>>

    for item in items.values_mut() {
        item.borrow_mut().foo_mut();
    }
}

我想现在并行调用trait方法,所以我首先改变了我的数据结构为:

use std::collections::*;
use std::sync::{Arc, RwLock};

fn main() {
    let mut items: HashMap<i32, Arc<RwLock<dyn Trait>>> = HashMap::new();

    for item in items.values_mut() {
        item.write().unwrap().foo_mut();
    }
}

然后我了解到了 rayon ,并尝试使用其并行迭代器,但是以下代码会产生一个错误:

items.par_iter_mut().for_each(|(id, item)| item.write().unwrap().foo_mut());

error[E0599]: no method named `par_iter_mut` found for struct `std::collections::HashMap<i32, std::sync::Arc<std::sync::RwLock<dyn Trait>>>` in the current scope
   --> src/main.rs:12:11
    |
12  |       items.par_iter_mut().for_each(|(id, item)| item.write().unwrap().foo_mut());
    |             ^^^^^^^^^^^^ help: there is an associated function with a similar name: `iter_mut`
    |
    = note: the method `par_iter_mut` exists but the following trait bounds were not satisfied:
            `&mut std::collections::HashMap<i32, std::sync::Arc<std::sync::RwLock<dyn Trait>>>: rayon::iter::IntoParallelIterator`
            which is required by `std::collections::HashMap<i32, std::sync::Arc<std::sync::RwLock<dyn Trait>>>: rayon::iter::IntoParallelRefMutIterator`

我查看了for_each的文档,它要求Self::Item必须是Send类型,并且闭包必须是Send + Sync类型。现在从我所见,Arc已经是Send + Sync类型了,但是可以通过像下面代码一样添加这两种特性来修复我的代码:

let mut items: HashMap<i32, Arc<RwLock<dyn Trait + Send + Sync>>> = HashMap::new();

为什么需要这个?

1个回答

5

Arc<T>SendSync 实现看起来像 this:

impl<T> Send for Arc<T>
where
    T: Send + Sync + ?Sized, 

impl<T> Sync for Arc<T>
where
    T: Send + Sync + ?Sized, 

这意味着只有当 T 也是 SendSync 时,Arc<T> 才是 SendSync (关于原因,请参见此处的解释)。
同样地,只有当 T 时,RwLock<T> 才是 SendSync
impl<T: ?Sized + Send> Send for RwLock<T>
impl<T: ?Sized + Send + Sync> Sync for RwLock<T>

综合来看,这意味着只有在 dyn Trait 满足 SendSync 的情况下,Arc<RwLock<dyn Trait>> 才会成为 SendSync。如果编写 dyn Trait + Send + Sync 很麻烦,并且您知道永远不会为任何不是 SendSync 的类型实现 Trait,则可以将这些作为约束添加到 trait 中:

trait Trait: Send + Sync {
    fn foo_mut(&mut self);
}

那么您原来的代码中使用 Arc<RwLock<dyn Trait>> 将可以与 rayon 一起工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接