You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何并行等待多个Rust Future并在首个Err出现时终止?

解决tokio::join首个Future失败时不立即返回的问题

tokio::join!的特性是等待所有传入的Future完成后才返回结果,哪怕其中某个已经返回Err,这和你需要的「首个失败立即完成」行为不符。下面提供两种符合需求的实现方式:

方式一:用tokio::try_join!(自动取消未完成任务)

tokio::try_join!专门处理这种场景:一旦任何一个Future返回Result::Err,它会立即返回该错误,同时取消所有未完成的Future。

示例代码:

use tokio;

async fn risky_task1() -> Result<(), String> {
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    Err("task1 failed early".to_string())
}

async fn long_running_task2() -> Result<(), String> {
    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
    Ok(())
}

#[tokio::main]
async fn main() {
    match tokio::try_join!(risky_task1(), long_running_task2()) {
        Ok((_res1, _res2)) => println!("All tasks succeeded"),
        Err(err) => {
            println!("First error encountered: {}", err);
            // 此时long_running_task2已被取消,不会继续执行到完成
        }
    }
}

注意:try_join!要求所有Future的返回值都是Result类型,且错误类型需要统一(可以用Box<dyn std::error::Error>来兼容不同错误类型)。

方式二:用tokio::select!(保留未完成任务继续运行)

如果你希望首个Future失败时立即返回结果,但让其他未完成的任务继续在后台执行(和JavaScript的Promise.all行为完全一致),可以结合tokio::spawn和tokio::select!实现:

示例代码:

use tokio;

async fn risky_task1() -> Result<(), String> {
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    Err("task1 failed early".to_string())
}

async fn long_running_task2() -> Result<(), String> {
    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
    println!("task2 completed successfully");
    Ok(())
}

#[tokio::main]
async fn main() {
    // 将任务放入后台任务中
    let mut task1_handle = tokio::spawn(risky_task1());
    let mut task2_handle = tokio::spawn(long_running_task2());

    // 等待第一个完成的任务(无论成功或失败)
    let first_result = tokio::select! {
        res = &mut task1_handle => res.unwrap(), // 处理spawn的JoinError
        res = &mut task2_handle => res.unwrap(),
    };

    match first_result {
        Err(err) => println!("First error encountered: {}", err),
        Ok(_) => println!("First task succeeded"),
    }

    // 如果需要等待task2完成,可取消下面的注释
    // let _ = task2_handle.await;
}

这种方式下,select!会在第一个任务完成时立即返回,未完成的任务会继续在后台运行直到结束。

内容的提问来源于stack exchange,提问作者programmerRaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:22:16