【问题标题】:rust tokio: calling async function from sync closurerust tokio:从同步闭包中调用异步函数
【发布时间】:2021-01-21 23:55:52
【问题描述】:

我有以下问题: 我正在尝试从async 函数调用sync 闭包,但sync closure 必须稍后调用另一个async 函数。

我无法进行异步关闭,因为它们目前不稳定: error[E0658]: async closures are unstable

所以我必须以某种方式这样做。

我发现了一些与该问题相关的问题,例如this,但是当我尝试实现它时,我收到以下错误:

Cannot start a runtime from within a runtime. 
This happens because a function (like `block_on`)
 attempted to block the current thread while the 
thread is being used to drive asynchronous tasks.'

这里是playground link,希望可以显示我遇到的问题。

我正在使用标题中所述的 tokio。

【问题讨论】:

  • 您可以创建一个返回异步块的闭包 - || async { ... } 而不是 async || { ... }
  • 详细说明,这是您的游乐场,建议进行更改:play.rust-lang.org/…
  • @Cerberus 非常感谢您,现在看来是要走的路了。只是为了将来的读者,我现在要发表评论,因为闭包返回异步块(而不是像以前那样正常)闭包应该用 .awat 调用

标签: asynchronous rust rust-tokio


【解决方案1】:

正如错误消息所述,Tokio 不允许您拥有嵌套运行时。

在 Tokio 的 Mutex 的文档中有一段说明如下 (link):

[It] 可以,并且通常更喜欢在异步代码中使用标准库中的普通 Mutex。 [...] 异步互斥锁相对于阻塞互斥锁提供的功能是可以将互斥锁锁定在 .await 点上,这对于数据来说很少需要。

另外,来自 Tokio 的 mini-Redis 示例:

Tokio 互斥锁主要用于需要持有锁的情况 跨越.await 屈服点。所有其他情况通常最好 由 std 互斥体提供服务。如果临界区不包括任何 异步操作但很长(CPU 密集型或执行阻塞 操作),然后是整个操作,包括等待互斥体, 被认为是“阻塞”操作和tokio::task::spawn_blocking 应该使用。

如果Mutex 是同步调用中唯一需要的async,则最好将其设置为阻塞Mutex。在这种情况下,您可以通过首先调用try_lock() 将其从async 代码中锁定,如果失败,则尝试通过spawn_blocking 将其锁定在阻塞上下文中。

【讨论】:

  • 这对我没有帮助,因为在互斥锁后面有async 套接字,我从异步函数和提到的闭包中写入。我想我可以让套接字同步,然后从每个试图写入这个套接字的异步函数中调用 spawn 阻塞,但这看起来很难看。