在c#的异步编程场景中,很多时候我们需要在执行耗时异步任务时支持中途取消的能力,比如用户主动终止操作、超时自动取消等,CancellationToken就是专门用于传递取消请求的类型,配合Task相关API可以实现异步任务的优雅取消。

CancellationToken核心相关类型
使用CancellationToken取消异步任务,需要了解两个核心类型:
- CancellationTokenSource:用于创建取消请求,管理取消状态,它可以触发取消操作,并且可以关联取消的回调和超时设置。
- CancellationToken:用于传递给异步方法,异步方法通过它检查是否收到了取消请求,本身不负责触发取消,只是传递取消信号。
基础用法:取消一个简单异步任务
下面通过一个示例演示如何创建取消请求,传递给异步任务,然后在外部触发取消,让异步任务停止执行。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// 创建CancellationTokenSource实例
using var cts = new CancellationTokenSource();
// 启动异步任务,传入CancellationToken
Task asyncTask = DoWorkAsync(cts.Token);
// 模拟等待1秒后触发取消
await Task.Delay(1000);
Console.WriteLine("触发取消请求");
cts.Cancel();
try
{
await asyncTask;
}
catch (OperationCanceledException)
{
Console.WriteLine("异步任务已被取消");
}
}
static async Task DoWorkAsync(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
// 检查是否收到取消请求
token.ThrowIfCancellationRequested();
Console.WriteLine($"执行第{i + 1}次操作");
await Task.Delay(500, token); // 传入token,让Delay也支持取消
}
}
}
上面的代码中,CancellationToken.ThrowIfCancellationRequested()方法会在收到取消请求时抛出OperationCanceledException异常,终止当前任务的执行。同时Task.Delay也传入了token,这样如果取消请求在延迟期间触发,延迟会直接结束,不会继续等待。
带超时的取消场景
很多时候我们需要异步任务执行超过一定时间后自动取消,不需要手动触发,这时候可以使用CancellationTokenSource的超时构造函数。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// 创建超时时间为2秒的CancellationTokenSource
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
try
{
await LongRunWorkAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("任务因超时被取消");
}
}
static async Task LongRunWorkAsync(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
Console.WriteLine("任务执行中...");
await Task.Delay(300, token);
}
}
}
注册取消回调
当取消请求触发时,我们可能需要执行一些清理操作,比如释放资源、更新状态等,这时候可以通过CancellationToken.Register方法注册回调。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var cts = new CancellationTokenSource();
// 注册取消回调
cts.Token.Register(() =>
{
Console.WriteLine("收到取消请求,执行清理操作");
});
Task task = DoWorkWithCleanupAsync(cts.Token);
await Task.Delay(800);
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务已取消");
}
}
static async Task DoWorkWithCleanupAsync(CancellationToken token)
{
for (int i = 0; i < 5; i++)
{
token.ThrowIfCancellationRequested();
Console.WriteLine($"执行步骤{i + 1}");
await Task.Delay(400, token);
}
}
}
使用注意事项
- CancellationTokenSource实现了IDisposable接口,使用完毕后应该及时释放,避免资源泄漏,建议使用using语句管理它的生命周期。
- 不要在异步方法中捕获
OperationCanceledException后不做处理直接吞掉异常,除非你明确知道不需要向上传播取消信号,否则应该让异常正常抛出,让上层知道任务被取消了。 - 如果一个异步方法接收了CancellationToken参数,就应该尽可能在方法内部的所有异步操作中传递这个token,保证整个调用链的取消能力是连贯的。
- 取消请求是协作式的,也就是说只有异步方法主动检查CancellationToken的状态,取消才会生效,无法强制终止一个不检查取消信号的异步任务。
常见问题解答
为什么取消时会抛出OperationCanceledException?
这是c#异步取消的标准设计,通过异常的方式传播取消信号,可以让取消逻辑和正常的业务逻辑分离,上层调用者可以通过捕获这个特定异常来处理取消后的逻辑,而不需要在每个方法里返回取消状态。
多个异步任务可以共用同一个CancellationToken吗?
可以,多个异步任务可以接收同一个CancellationToken,当取消请求触发时,所有关联的任务都会收到取消信号,适合需要批量取消多个相关任务的场景。
CancellationToken异步任务Taskcsharp取消操作修改时间:2026-07-07 20:33:26