#asynchronous #rust #concurrency
Вопрос:
Рассмотрим следующий код, который объявляет признак с 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(amp;self) -> Result<()>;
}
// ElectricMotor implements PowerSource.
struct ElectricMotor {}
impl PowerSource for ElectricMotor {
fn supply_power(amp;self) -> Result<()> {
println!("ElectricMotor::supply_power");
Ok(())
}
}
// A trait that describes a vehicle
#[async_trait]
trait Vehicle {
async fn drive(amp;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(amp;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(amp;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(amp;self) -> Result<()> {
| ^^^^ has type `amp;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(amp;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(amp;self) -> Result<()> {
| ^^^^ has type `amp;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
и Sync
, но я все еще очень новичок в параллелизме Rust и все еще не совсем понимаю, что это значит.
Как бы я исправил эту ошибку?
Ответ №1:
Вы должны изменить свое 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
Дополнительное чтение:
Комментарии:
1. Так просто, как только вы научитесь отделять деревья от леса. Спасибо.