multithreading - Rust - 将函数引用传递给线程
问题描述
假设我有一个类似的结构:
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
。
我可以做一个 hack,我可以将 包装Arc<dyn Fn(Vec<f64>) -> Vec<f64>
在 Wrapper 结构中,然后用Sync
using标记包装器unsafe impl
。但我想知道是否有比这更好的解决方案。
现在由于函数在 an 内部,Arc
我们可以保证函数值是不可变的。
我还可以保证向量的大小对于任何MyStruct
. 它可能是 2、3,也可能n
是相同的。所以向量的大小是恒定的。所以函数大小实际上是恒定的。
事实上,如果Vec<f64>
我不使用&[f64]
and ,即使切片具有确定的大小[f64]
,该函数仍然不会实现。Send
那么为什么不能在线程之间共享该函数,我该怎么做才能在线程之间真正共享它呢?
解决方案
为了将一个发送Arc
到另一个线程,Arc
需要实现Send
. 如果您查看文档,Arc
您会发现它有
impl<T> Send for Arc<T> where
T: Send + Sync + ?Sized {}
这意味着要使您的代码正常工作,您的T
( dyn Fn(Vec<f64>) -> Vec<f64>
) 需要实现Send
和Sync
.
由于您的类型是一个特征对象,您需要做的是声明,例如
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
类型实现了所有这三个特征:
Fn(Vec<f64>) -> Vec<f64>
Sync
Send
如果没有该Sync + Send
特征,您的f
函数可能会捕获对 a 的引用Cell
,这将导致竞争条件,因为多个线程可能会同时尝试更新单元格的值。您的代码很可能不会这样做,但是您的start
函数无法知道这一点,除非您告诉它f
受到足够的限制而不允许这样做。
推荐阅读
- c++ - 在链表中间插入的操作给了我一个错误的输出
- python - 教授提供的功能不输出任何东西
- nonlinear-optimization - 德雷克:非线性模型预测控制的任何教程或示例?
- html - 在 JSP 项目(HTML 和 JS)中使用 ReactJS 组件 (JSX)
- python - NameError:名称“按钮”未定义
- python - 使用条件获取列名,使用熊猫获取列值?
- python - 如何添加 github 文件夹的路径太 cdqa pdf_converter?或者从 python 中的 github 存储库中提取 pdf
- c++ - QAbstractNativeEventFilter 未收到 XCB_KEY_PRESS
- node.js - 如何停止使用 node 和 ejs 访问我的 index.html 文件
- bert-language-model - 不平衡或小数据集上的 BERT 分类