CancellationToken
是 C# 中用于取消异步任务的机制,广泛应用于任务并行库(Task Parallel Library,TPL)、异步方法以及其他需要支持取消操作的多线程场景。使用 CancellationToken
,可以在异步任务中提供一个取消信号,使得任务在必要时能够及时中止执行。
下面是 CancellationToken
的详细使用教程,涵盖其基本概念、使用方法以及一些高级应用场景。
目录
1. 什么是 CancellationToken
CancellationToken
是用于在异步或并行操作中传递取消请求的结构。它通常和 CancellationTokenSource
一起使用。CancellationTokenSource
是管理取消信号的对象,而 CancellationToken
则是用于检测是否收到取消请求的标志。
CancellationTokenSource
:生成并管理取消请求。CancellationToken
:由CancellationTokenSource
提供,任务使用它来检查取消信号。
2. 使用 CancellationToken
的步骤
-
创建
CancellationTokenSource
对象CancellationTokenSource
是用来生成CancellationToken
的对象,它控制取消信号。
-
将
CancellationToken
传递给异步任务CancellationToken
是通过CancellationTokenSource
提供的,用于向任务传递取消信号。
-
在任务中检查取消状态
- 任务需要定期检查
CancellationToken
,并在收到取消请求时,停止执行。
- 任务需要定期检查
-
请求取消
- 调用
CancellationTokenSource.Cancel()
来发出取消请求,通知关联的任务。
- 调用
3. 详细使用示例
3.1 创建并取消任务的基础示例
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 1. 创建 CancellationTokenSource
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
// 2. 启动任务并传递 token
Task task = Task.Run(() => DoWork(token), token);
// 模拟用户请求取消任务
Console.WriteLine("Press any key to cancel the task...");
Console.ReadKey();
// 3. 请求取消
cts.Cancel();
try
{
// 4. 等待任务完成
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was cancelled.");
}
finally
{
cts.Dispose();
}
Console.WriteLine("Main program has completed.");
}
static void DoWork(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
// 检查任务是否被取消
token.ThrowIfCancellationRequested();
Console.WriteLine($"Task working... {i}");
Thread.Sleep(500); // 模拟耗时操作
}
Console.WriteLine("Task completed.");
}
}
代码说明
- 创建
CancellationTokenSource
:用于管理取消操作。 - 传递
CancellationToken
:在任务启动时传递CancellationToken
,任务可以通过它检查是否有取消请求。 - 定期检查取消状态:使用
token.ThrowIfCancellationRequested()
检查任务是否被取消,并抛出OperationCanceledException
以中止任务。 - 发出取消请求:调用
cts.Cancel()
来通知任务取消。 - 处理取消异常:捕获
OperationCanceledException
以处理取消后的清理工作。
3.2 使用 token.IsCancellationRequested
检查取消状态
有时,不需要抛出异常,而是通过检查 token.IsCancellationRequested
来有条件地终止任务。
static void DoWork(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Task is cancelling...");
break; // 退出循环,停止任务
}
Console.WriteLine($"Task working... {i}");
Thread.Sleep(500); // 模拟耗时操作
}
Console.WriteLine("Task completed.");
}
3.3 设置超时取消任务
CancellationTokenSource
提供了一些辅助方法,比如设置超时来自动取消任务。
CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // 5秒后自动取消
CancellationToken token = cts.Token;
try
{
Task task = Task.Run(() => DoWork(token), token);
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Task was cancelled due to timeout.");
}
4. 进阶用法
4.1 合并多个 CancellationToken
有时一个任务可能同时需要响应多个取消请求,可以通过 CancellationTokenSource.CreateLinkedTokenSource
来合并多个 CancellationToken
。
CancellationTokenSource cts1 = new CancellationTokenSource();
CancellationTokenSource cts2 = new CancellationTokenSource();
// 合并两个 token
CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
CancellationToken token = linkedCts.Token;
Task task = Task.Run(() => DoWork(token), token);
// 发出取消请求
cts1.Cancel(); // 或 cts2.Cancel();
4.2 使用 CancellationToken
取消异步方法
异步方法也支持 CancellationToken
,可以在异步操作中使用。
static async Task DoWorkAsync(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
// 检查取消请求
token.ThrowIfCancellationRequested();
// 模拟异步操作
await Task.Delay(1000);
Console.WriteLine($"Working... {i}");
}
}
5. 注意事项
- 定期检查取消状态:在任务内部定期调用
token.ThrowIfCancellationRequested()
或token.IsCancellationRequested
来检测取消信号,确保任务能够及时响应取消请求。 - 取消任务的副作用:如果任务涉及到 I/O 操作、文件写入等,需要确保在取消后执行适当的清理工作,防止资源泄漏。
- 处理
OperationCanceledException
:通常使用try-catch
来捕获OperationCanceledException
,以确保任务取消后程序能正确处理。 - 不可取消的操作:一些耗时的阻塞操作(如
Thread.Sleep()
)是无法响应取消请求的,使用Task.Delay()
等非阻塞操作会更好地配合取消机制。
6. 总结
CancellationToken
为 C# 中的异步任务和并行操作提供了灵活的取消机制。通过合理地使用 CancellationTokenSource
和 CancellationToken
,可以让任务在适当的时刻取消执行,避免不必要的资源浪费。掌握如何通过 token.ThrowIfCancellationRequested()
和 token.IsCancellationRequested
检测取消请求,是异步和并发编程中的关键技巧。