cancellationtoken 不能直接取消代码,因为它仅提供协作式取消机制,要求目标代码主动检查 iscancellationrequested 或调用 throwifcancellationrequested;未检查则无法响应。

为什么 CancellationToken 不能直接取消正在运行的代码
因为 CancellationToken 本身不强制终止线程或中断执行,它只提供一种协作式取消机制——目标代码必须主动检查是否被请求取消。如果你调用 token.Cancel() 后任务仍在跑,大概率是没在关键位置轮询 token.IsCancellationRequested 或没传入支持取消的异步方法。
常见错误现象:Task.Delay(10000, token) 能响应取消,但自己写的 while (true) { Thread.Sleep(100); } 完全无视 token;或者忘了把 token 传进 HttpClient.GetAsync(..., token),导致网络请求卡死。
- 所有可取消的 .NET 异步方法(如
Task.Delay、HttpClient.SendAsync、Stream.ReadAsync)都接受CancellationToken参数,必须显式传入 - 自定义长时间运行逻辑,需定期检查
token.ThrowIfCancellationRequested()或token.IsCancellationRequested - 不要在非协作式操作(如 CPU 密集型循环、未封装的
Thread.Sleep)中依赖CancellationToken
CancellationTokenSource 的生命周期管理容易出什么问题
一个 CancellationTokenSource 只能调用一次 Cancel(),之后再调用会抛出 ObjectDisposedException;而且一旦取消,其 Token 就永远处于“已取消”状态,不能再复用。
典型误用:把同一个 CancellationTokenSource 实例反复用于多个独立任务;或在 using 块里创建它,却把 Token 暴露给外部长期存活的对象,导致 Dispose() 后 token 失效但调用方无感知。
- 每个需要独立取消语义的操作,应使用独立的
CancellationTokenSource - 如果任务可能重试,每次都要新建
CancellationTokenSource,而不是复用旧实例 - 避免跨
async方法边界持有对CancellationTokenSource的引用;更安全的做法是只传递CancellationToken
如何让同步阻塞操作也能响应取消
纯同步代码(比如调用第三方 SDK 的阻塞 API)无法直接响应 CancellationToken,但可以通过 Register 注册回调,在取消触发时执行中断动作(例如关闭句柄、设置退出标志)。
例如:你启动了一个子进程并用 Process.WaitForExit() 阻塞等待,这时可以注册回调来调用 process.Kill()。
- 用
token.Register(() => { /* 清理动作 */ })注册取消时的副作用,注意该委托运行在线程池线程上 - 注册后返回
Disposable对象,应在适当时候调用Dispose()解除绑定,否则可能造成内存泄漏 - 注册时机应在同步操作开始前,且确保注册和操作之间没有竞态(例如先注册再
Start()进程)
HttpClient 请求取消失败的常见原因
即使传了 CancellationToken,HttpClient 的请求仍可能不及时结束,尤其在 DNS 解析、TCP 连接建立、或服务器无响应阶段。
根本原因是底层 socket 操作受操作系统超时控制,.NET 层的取消只能中断“等待响应”的阶段,无法强制打断系统级连接过程。这也是为什么有时 Cancel() 后还要等几秒才抛出 OperationCanceledException。
- 确保
HttpClient实例是长生命周期复用的(避免每次新建),否则连接池失效,取消效果更差 - 配合设置
HttpClient.Timeout(默认 100 秒),它和CancellationToken是两套机制,可互补但不替代 - 若需更精细控制(如 DNS 超时),得换用
Socket+ConnectAsync等底层 API,并手动集成CancellationToken
复杂点在于取消不是“按下开关就停”,而是多方协作的结果:调用方发信号、API 实现方响应、操作系统配合、你自己还得处理好资源清理。最容易被忽略的是——忘记检查 IsCancellationRequested,或者以为传了 token 就万事大吉,结果卡在某个不支持取消的环节里干等。










