tokio::尝试加入! tokio::spawn 处理程序不会提前返回

问题描述 投票:0回答:1
#[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!
应该返回,然后程序应该关闭(其他正在运行的方法将终止)。

join rust try-catch spawn
1个回答
0
投票

这就是

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!
块中即可。

© www.soinside.com 2019 - 2024. All rights reserved.