Rayon文档说,它保证使用Rayon API不会引入数据争用。
编译器如何知道闭包调用的方法未共享可变状态,例如RefCell<T>
和Cell<T>
,或者使用非线程安全的结构(例如{{1 }}?
我知道Rc<T>
标记了可以在线程之间安全共享的类型,但是我不了解Rayon类型声明和编译器是如何执行的!
答案 0 :(得分:3)
您实际上回答了自己的问题–所有需要在线程之间共享的闭包都必须为Sync
,而Rayon的API只是要求它们通过特征界线为Sync
。例如,请参见documentation of ParallelIterator::map()
,该方法将方法指定为
fn map<F, R>(self, map_op: F) -> Map<Self, F> where
F: Fn(Self::Item) -> R + Sync + Send,
R: Send,
这里没有更深层次的魔术了-每当Rayon以要求Sync
的方式使用闭包时,例如通过将其传递给较低级别的API,Rayon限制了具有Sync
特征限制的相应参数类型。反过来,这确保了闭包中存储的所有内容都是Sync
,因此您不能在闭包中存储任何RefCell
。
在这种情况下,您也可以要求编译器提供解释。例如,如果您尝试编译此代码
use std::cell::RefCell;
use rayon::prelude::*;
fn main() {
let c = RefCell::new(5);
let _ = [1, 2, 3]
.par_iter()
.map(|i| i * *c.borrow())
.sum();
}
您会收到此错误(playground)
error[E0277]: `std::cell::RefCell<i32>` cannot be shared between threads safely
--> src/main.rs:10:10
|
10 | .map(|i| i * *c.borrow())
| ^^^ `std::cell::RefCell<i32>` cannot be shared between threads safely
|
= help: within `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`, the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<i32>`
= note: required because it appears within the type `&std::cell::RefCell<i32>`
= note: required because it appears within the type `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`
尽管不幸的是,编译器没有直接提及map()
的参数的特征绑定,但仍将您指向相关方法,并解释说它期望闭包为Sync
,并且不是的原因。