asynchronous - 如何对具有动态成员的结构采用 Send 和 Sync(未来无法在线程之间安全发送)
问题描述
考虑下面的代码,它使用crate声明了一个带有async
方法的特征。async-trait
use std::{io::Result, sync::Arc};
use async_trait::async_trait;
use tokio;
// A trait that describes a power source.
trait PowerSource {
fn supply_power(&self) -> Result<()>;
}
// ElectricMotor implements PowerSource.
struct ElectricMotor {}
impl PowerSource for ElectricMotor {
fn supply_power(&self) -> Result<()> {
println!("ElectricMotor::supply_power");
Ok(())
}
}
// A trait that describes a vehicle
#[async_trait]
trait Vehicle {
async fn drive(&self) -> Result<()>;
}
// An automobile has some kind of power source and implements Vehicle
struct Automobile {
power_source: Arc<dyn PowerSource>,
}
#[async_trait]
impl Vehicle for Automobile {
async fn drive(&self) -> Result<()> {
self.power_source.supply_power()?;
println!("Vehicle::Drive");
Ok(())
}
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let driver = ElectricMotor {};
let controller = Automobile {
power_source: Arc::new(driver),
};
controller.drive().await?;
Ok(())
}
这不会编译错误“未来无法在线程之间安全地发送”:
error: future cannot be sent between threads safely
--> src/main.rs:34:41
|
34 | async fn drive(&self) -> Result<()> {
| _________________________________________^
35 | | self.power_source.supply_power()?;
36 | | println!("Vehicle::Drive");
37 | | Ok(())
38 | | }
| |_____^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `(dyn PowerSource + 'static)`
note: captured value is not `Send`
--> src/main.rs:34:21
|
34 | async fn drive(&self) -> Result<()> {
| ^^^^ has type `&Automobile` which is not `Send`
= note: required for the cast to the object type `dyn Future<Output = Result<(), std::io::Error>> + Send`
error: future cannot be sent between threads safely
--> src/main.rs:34:41
|
34 | async fn drive(&self) -> Result<()> {
| _________________________________________^
35 | | self.power_source.supply_power()?;
36 | | println!("Vehicle::Drive");
37 | | Ok(())
38 | | }
| |_____^ future created by async block is not `Send`
|
= help: the trait `Send` is not implemented for `(dyn PowerSource + 'static)`
note: captured value is not `Send`
--> src/main.rs:34:21
|
34 | async fn drive(&self) -> Result<()> {
| ^^^^ has type `&Automobile` which is not `Send`
= note: required for the cast to the object type `dyn Future<Output = Result<(), std::io::Error>> + Send`
如果我正确理解错误,它认为这Automobile
不是Send
因为该power_source
属性不是,因此它不能创造一个适当的未来。我的理解是Arc
线程安全并实现了Send
and Sync
,但我对 Rust 并发性还是很陌生,仍然不完全清楚这意味着什么。
我将如何解决此错误?
解决方案
您必须修改Automobile
定义:
struct Automobile {
power_source: Arc<dyn PowerSource>,
}
在 rust 中,类型是Send
当且仅当其所有成员都是Send
(除非您手动且不安全地实现Send
)。这同样适用于Sync
。所以假设你power_source
的不是Send
,那么生成的impl Future
也不会是Send
。
修复它的方法是添加以下Send + Sync
要求power_source
:
struct Automobile {
power_source: Arc<dyn PowerSource + Send + Sync>,
}
但你为什么Sync
会问?Send
毕竟编译器只是在抱怨。它需要的原因Sync
是因为仅当两者兼有时才Arc<T>
实现Send
T
Send
Sync
补充阅读:
推荐阅读
- scala - Spark Scala Jupyter 笔记本全宽
- android - 在 ViewPager 抽屉布局中加载成像器的空指针 - 如何解决这个问题?
- javascript - 即使在缓存策略中提及关键字段后,useQuery 也不会缓存数据
- facebook - 是否可以仅针对 FB 页面中在给定日期有浏览量的帖子询问 FB Graph API?
- r - 在 R 中制作交互式多条形图(使用 SelectizeInput 和 Reactive)
- python - Plotly Python 排序表
- c++ - CMAKE target_include_directories 出现错误 C1083(找不到文件)
- node.js - 如何在 443 端口上配置多个进程?阿帕奇 - ubuntu
- templates - 具有多列的 XSLT 区域主体,强制块在新列上开始
- python - 如何在 pyspark 2.3 中的二元问题(BinaryClassificationEvaluator)中为 CrossValidator 评估器使用 f1-score