Rust-将函数引用传递给线程 [英] Rust - Pass a function reference to threads
问题描述
说我有一个类似的结构:
Say I have a struct like:
pub struct MyStruct {
f: Arc<dyn Fn(Vec<f64>) -> Vec<f64>>,
}
impl MyStruct {
pub fn new(f: Arc<dyn Fn(Vec<f64>) -> Vec<f64>>) -> MyStruct {
MyStruct { f }
}
pub fn start(&self) {
for _ in 0..5 {
let f = self.f.clone();
thread::spawn(move || {
let v: Vec<f64> = get_random_vector();
let v = (f)(v);
// do something with v
});
}
}
}
我收到一个错误消息,因为dyn Fn(Vec<f64>) -> Vec<f64>)
类型未实现Sync
,因此无法在线程之间安全地共享该函数.
I'm getting an error that the function cannot be shared between threads safely since the dyn Fn(Vec<f64>) -> Vec<f64>)
type doesn't implement Sync
.
我可以做一个黑客,可以将Arc<dyn Fn(Vec<f64>) -> Vec<f64>
包装在Wrapper结构中,然后使用unsafe impl
用Sync
标记包装.但是我想知道是否有比这更好的解决方案.
There is a hack that I can do where I can wrap the Arc<dyn Fn(Vec<f64>) -> Vec<f64>
in a Wrapper struct and then mark the wrapper with Sync
using unsafe impl
. But I was wondering if there is a better solution than that.
现在,由于函数位于Arc
内部,因此我们可以保证函数值是不变的.
Now since the function is inside an Arc
we have the guarantee that the function value is immutable.
我还可以保证向量的大小对于MyStruct
的任何实例始终是恒定的.它可能是2、3或n
,但将是相同的.因此,向量的大小是恒定的.因此,函数大小实际上是恒定的.
I can also guarantee that the size of the vectors will always be constant for any instance of MyStruct
. It might be 2, 3, or n
but it will be the same. So the size of the vector is constant. So the function size is de facto constant.
实际上,如果我使用的是&[f64]
和[f64]
而不是Vec<f64>
,则即使切片具有确定的大小,该函数仍不会实现Send
.
In fact, if instead of Vec<f64>
I use &[f64]
and [f64]
, the function will still not implement Send
, even though slices have a definite size.
那为什么不能在线程之间共享该函数,我该怎么做才能在线程之间共享呢?
So why can't the function be shared between threads and what can I do to indeed share it between threads?
推荐答案
为了将Arc
发送到另一个线程,Arc
需要实现Send
.如果您查看 Arc
的文档,则可以看到它有
In order to send an Arc
to another thread, the Arc
needs to implement Send
. If you look at the docs for Arc
you can see that it has
impl<T> Send for Arc<T> where
T: Send + Sync + ?Sized {}
这意味着要使您的代码正常工作,您的T
(dyn Fn(Vec<f64>) -> Vec<f64>
)需要实现Send
和Sync
.
which means that for your code to work, your T
(dyn Fn(Vec<f64>) -> Vec<f64>
) needs to implement Send
and Sync
.
由于您的类型是特征对象,因此您需要声明,例如
Since your type is a trait object, what you need to do is declare that, e.g.
pub struct MyStruct {
f: Arc<dyn Fn(Vec<f64>) -> Vec<f64> + Sync + Send>,
}
impl MyStruct {
pub fn new(f: Arc<dyn Fn(Vec<f64>) -> Vec<f64> + Sync + Send>) -> MyStruct {
MyStruct { f }
}
// ...
}
例如,T
类型实现了所有这三个特征:
as in, the T
type implements all three of these traits:
-
Fn(Vec<f64>) -> Vec<f64>
-
Sync
-
Send
Fn(Vec<f64>) -> Vec<f64>
Sync
Send
如果没有Sync + Send
特性,例如,您的f
函数可能会捕获对Cell
的引用,这会导致竞争状况,因为多个线程可能试图同时更新单元格的值.您的代码很可能不会这样做,但是您的start
函数无法知道这一点,除非您告诉它f
受到严格限制以不允许这样做.
Without the Sync + Send
trait, your f
function could for instance capture a reference to a Cell
, which would cause race conditions since multiple threads could potentially be trying to update the value of the cell at the same time. Your code may well not be doing that, but your start
function has no way of knowing that unless you tell it that f
is restricted enough to not allow that.
这篇关于Rust-将函数引用传递给线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!