Tokio错误:即使使用#[tokio::main]和单个版本的Tokio安装,仍然出现“没有正在运行的反应器”。

7
当运行以下代码时:
use futures::executor;
...
pub fn store_temporary_password(email: &str, password: &str) -> Result<(), Box<dyn Error>> {
  let client = DynamoDbClient::new(Region::ApSoutheast2);
  ...
  let future = client.put_item(input);
  executor::block_on(future)?; <- crashes here
  Ok(())
}

我遇到了错误:

thread '<unnamed>' panicked at 'there is no reactor running, must be called from the context of a Tokio 1.x runtime

我主函数上已经添加了tokio注解,如预期一样:

#[tokio::main]
async fn main() {
  ...

我的 cargo.toml 文件如下所示:
[dependencies]
...
futures = { version="0", features=["executor"] }
tokio = "1"

我的cargo.lock文件显示,我只有futures和tokio的一个版本(分别是"1.2.0"和"0.3.12")。

这已经涵盖了我在其他地方找到的有关此问题的所有解释。有任何想法吗?谢谢。


1
你不应该阻塞异步操作轮询的线程。如果你正在使用tokio执行器的async fn main,那么future.await就足够了,你不需要来自futures-rs的额外执行器。 - Ömer Erden
谢谢,但是我必须在我的代码库中将每个函数都变成异步函数吗?如果只有异步函数才能“等待”其他异步函数,那么似乎我需要彻底重构所有东西?我有什么遗漏的吗? - Chris
1
@Chris 是的,每个等待其他未来函数的函数都应该是异步的,否则你将执行阻塞操作。 - Ibraheem Ahmed
2
再次感谢 :) 做这件事的惯用方式是什么?人们真的会因为调用栈中深处的一个函数想要进行网络调用而改变大部分函数为“async”吗?诚实地说,我不确定,但对我来说似乎有些过度了。 :) - Chris
1
@Chris 我必须将代码库中的每个函数都变成异步的吗? 抱歉,我以为我已经编辑过我的上一个评论了。如果你使用 async fn main,这意味着你的主线程将被 tokio 执行器用于轮询。你可以随时创建一个新线程来处理非异步上下文。 - Ömer Erden
1个回答

6

在调用 block_on 之前,您必须先进入 tokio 运行时上下文:

let handle = tokio::runtime::Handle::current();
handle.enter();
executor::block_on(future)?;

注意,您的代码违反了异步函数不应长时间等待而不达到 .await 的规则。理想情况下,store_temporary_password 应标记为 async 以避免阻塞当前线程:
pub async fn store_temporary_password(email: &str, password: &str) -> Result<(), Box<dyn Error>> {
  ...
  let future = client.put_item(input);
  future.await?;
  Ok(())
}

如果没有其他选择,您应该将任何对 store_temporary_password 的调用包装在 tokio::spawn_blocking 中,以便在单独的线程池上运行阻塞操作。

非常感谢 :) 我明白阻塞不是理想的解决方案,但如果我将 store_temporary_password 改为异步,那么它的调用者也需要改为异步,以此类推吗? - Chris
1
@Chris 是的,基本上就是这样。编译器将 async 函数转换为高效的状态机,.await 点成为 yield 点,以便执行器(tokio)可以去处理其他事情而不会阻塞。您必须将函数标记为 async 才能利用此功能。 - Ibraheem Ahmed
再次感谢 :) 怎么做最符合惯用法?人们真的会因为调用栈深处的一个函数需要发起网络请求而将大部分函数更改为'async'吗?老实说,我不确定,但这似乎有点过重了 :) - Chris
@Chris,你正在使用tokio,所以你必须改变一切。如果你不是非常需要异步,你可以不使用tokio,而只需使用futures::executor::block_on - Ibraheem Ahmed
谢谢!不幸的是,rusoto使用tokio,所以没有其他AWS SDK可供选择。但除此之外,代码库的其余部分都不是异步的,因为它是一个AWS Lambda,没有太多需要。说实话,我可能会将所有内容都变成异步的。 - Chris
1
看起来 Rusoto 不需要 tokio,所以你可以使用 block_on 而不是使用 tokio。 - Ibraheem Ahmed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接