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

Rust是否具备与C#类似的Cancellation Token(取消令牌)机制?

在Rust中实现类似C# CancellationToken的优雅退出方案

你的问题核心是:无限循环未响应系统终止信号(如SIGTERM、SIGINT),导致操作系统只能等待超时后强制杀死进程,进而拉长重启耗时。Rust没有内置和C# CancellationToken完全一致的类型,但可以通过信号捕获+取消标记的组合实现等价的优雅退出逻辑,下面分同步、异步两种场景给出具体实现:

同步程序场景

依赖ctrlc crate捕获系统中断信号,配合原子布尔值作为取消标记,让循环能及时响应退出信号:

1. 添加依赖

在Cargo.toml中加入:

[dependencies]
ctrlc = "3.4"

2. 实现代码

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

fn main() {
    // 创建原子布尔值作为运行标记,线程安全
    let running = Arc::new(AtomicBool::new(true));
    let signal_handler_running = running.clone();

    // 注册信号处理函数:收到终止信号时将标记设为false
    ctrlc::set_handler(move || {
        signal_handler_running.store(false, Ordering::SeqCst);
        eprintln!("收到终止信号,准备退出循环");
    }).expect("无法设置信号处理器");

    // 带取消检查的无限循环
    while running.load(Ordering::SeqCst) {
        // 替换为你的任务逻辑
        println!("执行任务中...");
        // 注意:避免长时间阻塞,确保循环能定期检查标记
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    println!("循环已退出,程序优雅终止");
}

异步程序场景(基于Tokio)

Tokio提供了CancellationToken类型,结合信号捕获可以更简洁地实现异步任务的取消:

1. 添加依赖

[dependencies]
tokio = { version = "1.0", features = ["full"] }

2. 实现代码

use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::CancellationToken;

#[tokio::main]
async fn main() {
    let cancellation_token = CancellationToken::new();
    let token_clone = cancellation_token.clone();

    // 后台线程捕获SIGTERM和SIGINT信号,触发取消
    tokio::spawn(async move {
        let mut sigterm = signal(SignalKind::terminate()).expect("无法捕获SIGTERM");
        let mut sigint = signal(SignalKind::interrupt()).expect("无法捕获SIGINT");

        tokio::select! {
            _ = sigterm.recv() => {
                eprintln!("收到SIGTERM,触发任务取消");
                token_clone.cancel();
            }
            _ = sigint.recv() => {
                eprintln!("收到SIGINT,触发任务取消");
                token_clone.cancel();
            }
        }
    });

    // 带取消检查的异步循环
    loop {
        tokio::select! {
            // 等待取消信号触发
            _ = cancellation_token.cancelled() => {
                eprintln!("取消信号生效,退出循环");
                break;
            }
            // 执行你的异步任务
            _ = tokio::time::sleep(tokio::time::Duration::from_secs(1)) => {
                println!("执行异步任务中...");
            }
        }
    }

    println!("程序优雅终止");
}

关键注意事项

  • 循环中不能有过长时间的阻塞操作,否则即使收到终止信号,也无法及时检查取消标记。如果必须使用阻塞IO,建议设置超时或改用非阻塞API。
  • 系统重启时,OS会先发送SIGTERM给进程,等待一段超时时间后才会发送SIGKILL强制杀死进程。优雅退出逻辑能让进程在收到SIGTERM后立即停止,大幅缩短重启耗时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:30:30