尽管作用域拥有变量的所有权,但引用在被使用后仍被保留。

我有一些看起来像这样的代码。

async move {
    let res = do_sth(&state).await;
    (state, res)
}.boxed()

(完整的例子: https:/gitlab.commsrd0async-issue)

我想说的是 async move 块的所有权。state 并传递一个 state 伴随 do_sth 方法,它是一个 async fn. 然而,编译器也保留了 &state 跨越 await 绑定,我不知道它为什么会这样做。

error: future cannot be sent between threads safely
  --> src/main.rs:30:5
   |
30 |         }.boxed()
   |           ^^^^^ future returned by `read_all` is not `Send`
   |
   = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/main.rs:28:14
   |
28 |             let res = do_sth(&state).await;
   |                       ^^^^^^^------^^^^^^^- `&state` is later dropped here
   |                       |      |
   |                       |      has type `&gotham::state::State`
   |                       await occurs here, with `&state` maybe used later

我试着把 do_sth 呼叫 await 到它自己的块中,但这并没有解决这个错误。

有什么办法可以避免这个错误吗?

解决方案:

这个错误很明显与所有权或寿命无关。

error: future cannot be sent between threads safely

gotham_restful::State 没有实现 Sync 特质,这意味着它的参照物 &state 是不线程安全的。但是,你将该引用传递给异步函数,然后该函数被等待,Rust编译器会自动推断该函数不是线程安全的,所以整个块变得 “不是线程安全”。Rust编译器的 read_all 方法有 + Send 约束,但是,要求返回的future是线程安全的,所以这会导致错误。


一个可能的解决方案是重写 do_sth 成为一个返回未来的常规函数。这样你就可以确保从该函数返回的future实现了 Send 是线程安全的,而不是依靠编译器来推断它的线程安全与否。

fn do_sth(_state: &State) -> impl Future<Output = NoContent> + Send {
//   require that the future of this function is thread-safe ---^

    async move {
        Default::default()
    }
}

请注意,这实际上并不允许你做任何非线程安全的事情,但是它将指示编译器说 do_sth 函数应该是线程安全的,而不是试图手动推断它是否应该是安全的。

给TA打赏
共{{data.count}}人
人已打赏
未分类

将Arduino指南针信号转换为可用的航向。

2022-9-7 22:11:24

未分类

用 "TAP "设计模式执行许多长期运行的任务。

2022-9-7 22:22:18

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索