Rust 异步取消
(&mut join_handle).await
JoinHandle
通过 spawn task 实现超时取消
timer.rs
use std::future::Future;
pub async fn sleep(n: u64) {
tokio::time::sleep(std::time::Duration::from_millis(n)).await;
}
pub async fn timeout<T>(task: impl Future<Output = T> + Send + 'static, millis: u64) -> Option<T>
where
T: Send + 'static,
{
let mut join_handle = tokio::spawn(task);
tokio::select! {
Ok(v) = &mut join_handle => Some(v),
() = sleep(millis) => {
join_handle.abort();
None
},
}
}
测试
mod timer;
use timer::{sleep, timeout};
#[derive(Debug)]
struct A;
impl Drop for A {
fn drop(&mut self) {
println!("drop A, 任务结束或被取消")
}
}
#[tokio::main]
async fn main() {
match timeout(
async {
let _a = A;
println!("开始");
sleep(5000).await; // 模拟任务耗时,5秒
println!("完成");
12345
},
2000, // 超时时间,2秒
)
.await
{
Some(v) => {
println!("结果:{v}");
}
None => {
println!("超时");
}
}
println!("程序运行结束");
}
运行结果:
开始
drop A, 任务结束或被取消
超时
程序运行结束
我们增加超时时间大于5秒,结果:
开始
完成
drop A, 任务结束或被取消
结果:12345
程序运行结束
能否不使用 spawn
使用 tokio 官方功能吧!
#[derive(Debug)]
struct A;
impl Drop for A {
fn drop(&mut self) {
println!("drop A, 任务结束或被取消")
}
}
#[tokio::main]
async fn main() {
match tokio::time::timeout(std::time::Duration::from_millis(5000), async {
let _a = A;
println!("开始");
std::future::pending::<()>().await; // 永远不会被解决的未来
println!("完成");
12345
}).await {
Ok(v) => {
println!("结果:{v}");
}
Err(_) => {
println!("超时");
}
}
println!("程序运行结束");
}
结果:
开始
drop A, 任务结束或被取消
超时
程序运行结束
see
https://blog.yoshuawuyts.com/async-cancellation-1/