2

我已经开始了多项任务,tokio::spawn我想收集他们退出的原因dyn std::error::Error

如果任何任务恐慌,我想立即转发恐慌而不等待其他任务。为了实现这一点,我曾经在传播恐慌时futures::map展开。tokio::JoinHandle

然后我过去常常tokio::join!同时等待所有期货。

use futures::FutureExt;

#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        foo().await;
    })
    .await
    .unwrap();
}

async fn foo() {
    // Start two tasks.
    let worker1 = tokio::spawn(bar(1)).map(|res| res.unwrap());
    let worker2 = tokio::spawn(bar(2)).map(|res| res.unwrap());

    // Wait for all started tasks at once.
    // This doesn't compile.
    let (error1, error2) = tokio::join!(worker1, worker2);

    // This does compile, but panics only after 5 seconds.
    // let error1 = worker1.await;
    // let error2 = worker2.await;

    // Ignore in this example.
    let _: Box<dyn std::error::Error + Send> = error1;
    let _: Box<dyn std::error::Error + Send> = error2;
}

async fn bar(id: u8) -> Box<dyn std::error::Error + Send> {
    if id == 1 {
        tokio::time::sleep(core::time::Duration::from_secs(5)).await;
        Box::new(std::io::Error::last_os_error())
    } else {
        panic!("Not yet implemented");
    }
}

它给了我一个编译错误:

error: implementation of `FnOnce` is not general enough
 --> src/main.rs:5:5
  |
5 |     tokio::spawn(async move {
  |     ^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
  |
  = note: closure with signature `fn(Result<Box<(dyn std::error::Error + std::marker::Send + '0)>, JoinError>) -> Box<dyn std::error::Error + std::marker::Send>` must implement `FnOnce<(Result<Box<(dyn std::error::Error + std::marker::Send + '1)>, JoinError>,)>`, for any two lifetimes `'0` and `'1`...
  = note: ...but it actually implements `FnOnce<(Result<Box<dyn std::error::Error + std::marker::Send>, JoinError>,)>`

我正在与rustc 1.56.1 (59eed8a2a 2021-11-01). 我的 Cargo.toml 有:

tokio = { version = "1.12", features = ["full"] }
futures = "0.3"

我希望了解此错误或至少找到替代解决方案。

4

0 回答 0