#[tokio::main]
async fn main() -> io::Result<()> {
// ...
let handle1 = tokio::spawn( async move {method1().await });
let handle2 = tokio::spawn( async move {method2().await });
let handle3 = tokio::spawn( async move {method3().await });
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(handle1, handle2, handle3)?;
match handle1_ret {
Ok(_) => info!("handle1 closed");
Err(e) => error!("handle1 failed");
}
match handle2_ret {
Ok(_) => info!("handle2 closed");
Err(e) => error!("handle2 failed");
}
match handle3_ret {
Ok(_) => info!("handle3 closed");
Err(e) => error!("handle3 failed");
}
Ok(())
}
即使存在来自 tokio::try_join!
/
method1
/
method2
的错误,
method3
也卡在那里。
我想要的是,如果
method1
或method2
或method3
出现任何错误,tokio::try_join!
应该返回,然后程序应该关闭(其他正在运行的方法将终止)。
这就是
try_join!
的设计目的。您没有真正看到它的原因是您的 handle{1,2,3}
任务实际上返回了 Result
中的 Result
。您的 method{1,2,3}
调用可能会返回错误,但 tokio::spawn
本身也可能返回错误(由于生成失败或任务恐慌)。所以你真的是 .await
-ing 一个 Result<Result<_, _>, _>
并且 try_join!
只会处理外部 Result
。
要让
try_join!
处理您的 method{1,2,3}
错误,您需要“展平”您的 Result
。一个相当简单的方法是忽略任何 tokio::spawn
错误,因为这些错误通常是不可恢复的:
let handle1 = tokio::spawn(async move { method1().await });
let handle2 = tokio::spawn(async move { method2().await });
let handle3 = tokio::spawn(async move { method3().await });
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(
async { handle1.await.unwrap() },
async { handle2.await.unwrap() },
async { handle3.await.unwrap() },
)?;
或者如果你有一个空洞的错误类型(
Box<dyn Error>
,anyhow
等)或者有一个From
impl for JoinError
,你当然可以使用?
:
let (handle1_ret, handle2_ret, handle3_ret) = tokio::try_join!(
async { handle1.await? },
async { handle2.await? },
async { handle3.await? },
)?;
或者通过
Result
、match
在 if let
上进行任何其他模式匹配,或者任何可以让您根据需要进行处理的内容。它只需要位于您传递给 async { }
的 try_join!
块中即可。