问题起因
想要通过 trait object
调用 Trait
中定义的 async method(s)
(async fn
通过 async-trait 模拟实现)
示例代码如下
use async_std::task;
use async_trait::async_trait;
#[async_trait]
trait Foo {
async fn foo(&self);
}
struct A;
#[async_trait]
impl Foo for A {
async fn foo(&self) {
println!("foo A")
}
}
fn main() {
task::block_on(async {
task::spawn(async {
let a = A;
// 直接通过 A 调用 foo 没有问题
a.foo().await;
let o = &a as &dyn Foo;
// 通过 trait object 编译错误如下
o.foo().await;
}).await
});
}
编译错误如下
error: future cannot be sent between threads safely
--> examples/example.rs:20:9
|
20 | task::spawn(async {
| ^^^^^^^^^^^ future created by async block is not `Send`
|
::: /Users/dian/.cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/async-std-1.6.3/src/task/spawn.rs:28:29
|
28 | F: Future<Output = T> + Send + 'static,
| ---- required by this bound in `async_std::task::spawn::spawn`
|
= help: the trait `std::marker::Sync` is not implemented for `dyn Foo`
note: future is not `Send` as this value is used across an await
--> examples/example.rs:24:13
|
23 | let o = &a as &dyn Foo;
| - has type `&dyn Foo` which is not `Send`
24 | o.foo().await;
| ^^^^^^^^^^^^^ await occurs here, with `o` maybe used later
25 | }).await
| - `o` is later dropped here
error: aborting due to previous error
错误原因分析
回过头来看错误提示非常明显
the trait
std::marker::Sync
is not implemented fordyn Foo
note: future is notSend
as this value is used across an await
由于 trait object
没有 impl
Sync
Trait 导致了 o.foo()
返回的匿名 Future
不满足 Send
约束,进而无法在 async_std::task::spawn
中调用 await
。
理解问题的关键在于理解这句话
对于任意类型 T,如果 &T(T 的引用)是 Send 的话 T 就是 Sync 的
对应代码规则见 Sync
的定义
mod impls {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Sync + ?Sized> Send for &T {
}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: Send + ?Sized> Send for &mut T {
}
}
对于我们这里来说就是,想要 &dyn Foo
满足 : Send
约束则 dyn Foo
需要满足 : Sync
,修改类型转换代码如下
let o = &a as &(dyn Foo + Sync);
问题延伸
问题的根本原因在于有 !Send
的值跨越 await
导致生成的匿名 Future
也是 !Send
继而无法在线程之间传递
如果某结构体内部存在 !Sync
的字段,那么跨越 await
依然有问题,如下所示
struct C(Mutex<RefCell<i32>>);
impl C {
async fn bar(&self) {
println!("bar C");
}
}
#[async_trait]
impl Foo for C {
async fn foo(&self) {
let mut mg = self.0.lock().expect("lock");
let c = mg.get_mut();
// 跨越 await 则无法编译通过
// self.bar().await;
*c = 10;
}
}