Rust + Tokio 异步实战:select! 多路等待、任务取消与优雅退出

test12026-09-130 次阅读

问题背景

异步服务常需要"等任意一个条件先满足":超时、外部信号、子任务完成。Tokio 的 select! 宏能在多个异步分支中只等待第一个完成的,其余分支被丢弃,非常适合做超时控制与优雅关闭。

select! 做超时

use tokio::time::{sleep, Duration};
use tokio::sync::oneshot;

#[tokio::main]
async fn main() {
    let (tx, rx) = oneshot::channel::<()>();

    tokio::select! {
        _ = sleep(Duration::from_secs(3)) => {
            println!("超时:任务被取消");
        }
        _ = rx => {
            println!("收到信号,正常退出");
        }
    }
}

用 JoinHandle 主动取消任务

use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    let handle = tokio::spawn(async {
        loop {
            println!("工作中…");
            sleep(Duration::from_secs(1)).await;
        }
    });

    sleep(Duration::from_millis(500)).await;
    handle.abort(); // 显式取消,任务立即结束
    let _ = handle.await; // 拿到 JoinError(Cancelled)
}

配合信号做优雅退出

use tokio::signal;

#[tokio::main]
async fn main() {
    let ctrl_c = async {
        signal::ctrl_c().await.ok();
    };

    tokio::select! {
        _ = ctrl_c => println!("收到 Ctrl+C,开始回收资源"),
        _ = serve() => {},
    }
}

async fn serve() {
    // 主服务循环
}

要点

  • select! 中未完成的 Future 会被 drop,其内部持有的资源随之释放;注意闭包捕获的变量所有权。
  • abort 是"硬取消",不会执行被取消任务里的 defer 逻辑,关键清理要放到 select 之外或监听取消信号。
  • 用 biased; 修饰符可改变分支轮询优先级,避免某些分支永远饿死。
T

test1

文章作者

问题背景 异步服务常需要"等任意一个条件先满足":超时、外部信号、子任务完成。Tokio 的 select! 宏能在多...

分类
技术
发布时间
2026-09-13
字数
约 1267 字
阅读
0 次