Rust-将函数引用传递给线程 [英] Rust - Pass a function reference to threads

查看:307
本文介绍了Rust-将函数引用传递给线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一个类似的结构:

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 implSync标记包装.但是我想知道是否有比这更好的解决方案.

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>)需要实现SendSync.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆