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

发布时间 - 2025-12-29 00:00:00    点击率:
CancellationToken 本身不能取消任务,只是传递取消信号;真正取消依赖代码主动响应——检查 token 并抛出 OperationCanceledException 或提前退出。

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

怎么创建和传递 CancellationToken?

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

  • CancellationTokenSource 是“发号施令的人”,调用 Cancel()CancelAfter(3000) 就是下命令
  • CancellationToken 是“传令兵”,只读、不可变,任务靠它轮询或注册回调
  • 别自己 new CancellationToken —— 必须从 CancellationTokenSource.Token 获取

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

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

  • 你用的大多数 .NET 基础类库(FileStreamTask.DelayTimer 等)都原生支持 CancellationToken
  • 但你自己写的长循环、CPU 密集型计算、或调用非托管代码时,必须手动检查,否则取消完全无效
  • 错误写法:await Task.Delay(1000); —— 没传 token,就无法被外部中断
  • 正确写法:await Task.Delay(1000, token); 或在循环中加 token.ThrowIfCancellationRequested();

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

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

  • OperationCanceledException 是正常流程,不是 bug,应该显式 catch 并区分处理(比如不记日志、不弹错误框)
  • 别在 catch (Exception) 里吞掉 OperationCanceledException,否则你永远不知道任务是不是被取消了
  • 要用 token.Register(() => { /* 清理资源 */ }) 注册回调,尤其当取消可能发生在非 await 路径(如同步计算中途)
  • 超时场景优先用 new CancellationTokenSource(TimeSpan.FromSeconds(5)),比手写定时器 + Cancel() 更可靠
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 只提供机制,不替你做决策。


# go  #   # ai  # nas  # stream  # 微软  # 异步任务  # c#  # .net  # 为什么  # try  # catch  # Token  # register  # 循环  # using  # finally  # FileStream  # 异步  # 数据库  # bug  # 回调  # 抛出  # 的人  # 的是  # 这是  # 是个  # 还在  # 约定俗成  # 发号施令  # 死了 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 佛山企业网站制作公司有哪些,沟通100网上服务官网?  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  python中快速进行多个字符替换的方法小结  如何在Ubuntu系统下快速搭建WordPress个人网站?  Laravel如何使用Eloquent进行子查询  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  如何在宝塔面板创建新站点?  Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置  微信小程序 闭包写法详细介绍  如何用5美元大硬盘VPS安全高效搭建个人网站?  Laravel中的Facade(门面)到底是什么原理  如何在建站宝盒中设置产品搜索功能?  如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】  Laravel用户密码怎么加密_Laravel Hash门面使用教程  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  如何快速搭建高效WAP手机网站吸引移动用户?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  JavaScript如何实现继承_有哪些常用方法  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像  如何在阿里云部署织梦网站?  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  如何在IIS中新建站点并配置端口与物理路径?  昵图网官网入口 昵图网素材平台官方入口  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  昵图网官方站入口 昵图网素材图库官网入口  如何在搬瓦工VPS快速搭建网站?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  Python进程池调度策略_任务分发说明【指导】  如何解决hover在ie6中的兼容性问题  Laravel怎么在Blade中安全地输出原始HTML内容  怎么用AI帮你设计一套个性化的手机App图标?  JavaScript如何实现错误处理_try...catch如何捕获异常?  Laravel如何记录自定义日志?(Log频道配置)  Laravel路由怎么定义_Laravel核心路由系统完全入门指南  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  高防服务器租用指南:配置选择与快速部署攻略  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  三星网站视频制作教程下载,三星w23网页如何全屏?  详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)  深圳网站制作平台,深圳市做网站好的公司有哪些?  PHP 500报错的快速解决方法  如何在香港免费服务器上快速搭建网站?  Python企业级消息系统教程_KafkaRabbitMQ高并发应用  Laravel如何创建自定义中间件?(Middleware代码示例)