使用人造丝并行迭代器时的同步和发送特性

Nic*_*ick 3 synchronization iterator rust

我有我的特征集合,我希望能够为地图中的每个项目调用特征的可变方法。

目前我按顺序执行此操作,我的收藏如下所示:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在想并行调用 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我遇到了rayon,我尝试使用它的并行迭代器,但以下代码引发错误:

items.par_iter_mut().for_each(|(id, item)| item.write().unwrap().foo_mut());
Run Code Online (Sandbox Code Playgroud)
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`
Run Code Online (Sandbox Code Playgroud)

我检查了for_each文档,它需要Self::ItemSend和闭包是Send + Sync,现在我可以看到Arc is already Send + Sync,但是可以通过将这两个特征添加到我的中来修复代码,例如:

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`
Run Code Online (Sandbox Code Playgroud)

为什么这是必要的?

Bre*_*rby 5

SendSyncfor的实现Arc<T>如下所示

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

impl<T> Sync for Arc<T>
where
    T: Send + Sync + ?Sized, 
Run Code Online (Sandbox Code Playgroud)

这意味着,Arc<T>只有SendSyncT过(见这里 对于为什么的解释)。

同样,RwLock<T>SendSync如果T

impl<T: ?Sized + Send> Send for RwLock<T>
impl<T: ?Sized + Send + Sync> Sync for RwLock<T>
Run Code Online (Sandbox Code Playgroud)

总之,这意味着Arc<RwLock<dyn Trait>>只会是SendSync如果dyn Trait也是。如果编写起来很麻烦,dyn Trait + Send + Sync并且您知道您永远不想Trait为任何类型实现are not Sendor Sync,那么您可以将这些作为边界添加到特征中:

trait Trait: Send + Sync {
    fn foo_mut(&mut self);
}
Run Code Online (Sandbox Code Playgroud)

然后您的原始代码 withArc<RwLock<dyn Trait>>将与rayon.