贝利信息

c# CancellationToken 的用法 c#如何取消一个异步任务

日期:2025-12-29 00:00 / 作者:月夜之吻
CancellationToken 本身不能取消任务,只是传递取消信号;真正取消依赖代码主动响应——检查 token 并抛出 OperationCanceledException 或提前退出。

直接说结论:CancellationToken 本身不能“取消”任务,它只是个信号令牌;真正实现取消的是你写的代码是否响应这个信号——不检查、不抛异常、不退出,Cancel() 就是按了个静音键。

怎么创建和传递 CancellationToken?

核心就三步:建 CancellationTokenSource → 拿 Token → 往异步方法里传。绝大多数内置异步 API(比如 HttpClient.GetAsyncStreamReader.ReadLineAsync)都支持接收 CancellationToken 参数,这是约定俗成的最后一个可选参数。

为什么 await HttpClient.GetAsync(token) 会真的被取消?

因为 HttpClient 内部做了响应:它在底层 socket 操作中监听了 token.IsCancellationRequested,一旦为 true 就立即中断请求并抛出 OperationCanceledException。这不是魔法,是微软在 SDK 里写死了的协作逻辑。

常见踩坑:取消后任务还在跑、没进 catch、资源没释放

最典型的问题不是“不会用”,而是“用了但没全覆盖”。比如在 try 里开了文件流、连了数据库,却只在 await 处检查 token,忘了在 finally 或 using 外做清理。

static async Task LongRunningOperationAsync(CancellationToken token)
{
    using var registration = token.Register(() => Console.WriteLine("已触发取消回调,释放资源"));
for (int i = 0; i zuojiankuohaophpcn 100; i++)
{
    token.ThrowIfCancellationRequested(); // 关键:主动抛异常,让调用栈快速退出
    await Task.Delay(100, token);          // 关键:所有 await 都带 token
    Console.WriteLine($"进度: {i + 1}%");
}

}

真正难的从来不是怎么写 cts.Cancel(),而是想清楚:你的业务逻辑里,哪些步骤可中断、哪些必须原子完成、哪些资源必须确保释放——CancellationToken 只提供机制,不替你做决策。