Rust中进度反馈与取消机制的惯用实现方式
Rust中进度反馈与取消机制的惯用做法
一、取消机制
同步场景
Rust标准库没有内置类似C# CancellationToken的类型,但社区有成熟的实现方式:
- 使用
tokio::sync::CancellationToken(即使同步代码也能直接用,无需依赖异步runtime的其他功能),在函数的关键检查点调用ct.is_cancelled()判断是否需要终止执行,示例:
use tokio::sync::CancellationToken; fn long_running_fun(actual_param: i32, ct: &CancellationToken) -> Result<(), ()> { for i in 0..100 { if ct.is_cancelled() { return Err(()); } // 执行耗时操作 std::thread::sleep(std::time::Duration::from_millis(10)); } Ok(()) }
- 若不想引入Tokio依赖,也可以用
Arc<std::sync::atomic::AtomicBool>作为取消标记,每次迭代通过load(Ordering::Relaxed)检查状态。
注意:不要为了获取取消机制强行写异步代码,同步场景用同步的取消方案更符合Rust风格,异步是为IO密集或并发场景设计的,没必要硬套。
异步场景
Tokio等异步runtime支持通过JoinHandle::abort()直接取消任务,但如果需要函数内部主动响应取消(比如清理资源),推荐在函数参数中传入CancellationToken,或者用tokio::select!监听取消信号:
use tokio::sync::CancellationToken; use tokio::time::{sleep, Duration}; async fn long_running_fun_async(actual_param: i32, ct: CancellationToken) -> Result<(), ()> { for i in 0..100 { tokio::select! { _ = sleep(Duration::from_millis(10)) => {}, _ = ct.cancelled() => { // 执行资源清理 return Err(()); } } } Ok(()) }
二、进度反馈
Rust标准库没有类似C# IProgress<T>的标准trait,社区常用的实现方式有两种:
1. 传递回调函数
这是最直接的方式,函数接受一个可变闭包作为进度回调,内部在关键节点调用闭包传递进度:
fn long_running_fun_with_progress(actual_param: i32, mut progress: impl FnMut(f64)) { // 执行第一步,完成25% progress(0.25); // 执行第二步,完成50% progress(0.5); // 后续步骤... progress(1.0); }
如果需要处理回调可能返回的错误,可以把闭包定义为impl FnMut(f64) -> Result<(), E>,函数内部处理错误并提前返回。
2. 使用通道传递进度
如果进度需要跨线程或异步任务传递,可以用std::sync::mpsc(同步)或tokio::sync::mpsc(异步)通道:
use std::sync::mpsc; use std::thread; use std::time::Duration; fn long_running_fun_channel(actual_param: i32, sender: mpsc::Sender<f64>) -> Result<(), mpsc::SendError<f64>> { sender.send(0.0)?; thread::sleep(Duration::from_millis(100)); sender.send(0.5)?; thread::sleep(Duration::from_millis(100)); sender.send(1.0)?; Ok(()) } // 调用方示例 let (sender, receiver) = mpsc::channel(); thread::spawn(move || { long_running_fun_channel(42, sender).unwrap(); }); for progress in receiver { println!("进度: {}%", progress * 100.0); }
社区工具
如果是终端场景的进度展示,indicatif crate提供了开箱即用的进度条组件,无需自己实现进度传递逻辑。
总结
- 同步耗时函数:用
CancellationToken或原子布尔做取消,回调函数/通道做进度反馈; - 异步函数:结合runtime的取消机制,配合
CancellationToken主动响应取消,进度反馈同样用回调或通道; - 避免为了取消强行异步,同步场景用同步方案更符合Rust惯用风格。
内容的提问来源于stack exchange,提问作者Dune
相关产品推荐
相关产品推荐

