【问题标题】:Tokio error: "there is no reactor running" even with #[tokio::main] and a single version of tokio installedTokio 错误:即使安装了 #[tokio::main] 和单个版本的 tokio,“没有反应器正在运行”
【发布时间】:2021-02-23 06:26:20
【问题描述】:

当运行这样的代码时:

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

我的 main 应该有 tokio 注释:

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

我的 cargo.toml 看起来像:

[dependencies]
...
futures = { version="0", features=["executor"] }
tokio = "1"

我的 cargo.lock 显示我只有一个版本的期货和 tokio(分别为“1.2.0”和“0.3.12”)。

这用尽了我在其他地方找到的关于这个问题的解释。有任何想法吗?谢谢。

【问题讨论】:

  • You shouldn't block the thread where async operations meant to poll。如果您将 async fn main 与 tokio 执行器一起使用,future.await 应该就足够了,您不需要来自 futures-rs 的额外执行器。
  • 谢谢,但是我必须使我的代码库中的每个函数都异步吗?如果只有异步函数可以“等待”其他异步函数,那么我似乎必须彻底重构所有内容?我错过了什么吗?
  • @Chris 是的,等待其他未来的每个函数都应该是异步的,否则您将执行阻塞操作。
  • 再次感谢 :) 这样做的惯用方法是什么?人们真的会因为调用堆栈中的一个函数想要进行网络调用而最终将他们的大部分函数更改为“异步”吗?诚实的问题,我不确定,但对我来说似乎很沉重。 :)
  • @Chris 我必须让我的代码库中的每个函数都异步? 抱歉,我以为我编辑了我之前的评论,如果您使用的是 asyn fn main,这意味着您的主线程将用于 tokio executor 的轮询。你总是可以创建一个新线程来处理你的非异步上下文

标签: rust rust-tokio


【解决方案1】:

在调用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 是的,这就是它的工作原理。编译器将async 函数变成了一个非常高效的状态机,.await 点变成了屈服点,这样执行器(tokio)就可以处理其他事情而不是阻塞。您必须将您的函数标记为 async 才能利用这一点。
  • 再次感谢 :) 这样做的惯用方法是什么?人们真的会因为调用堆栈中的一个函数想要进行网络调用而最终将他们的大部分函数更改为“异步”吗?诚实的问题,我不确定,但对我来说似乎很沉重。 :)
  • @Chris 好吧,你正在使用 tokio,所以你必须改变一切。如果你真的不想要/不需要异步,你可以不使用 tokio 而只使用 futures::executor::block_on 一切。
  • It seems like Rusoto does not require tokio,所以您可以只使用block_on 而不是使用 tokio。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 2022-11-03
  • 2022-06-19
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多