在现代异步编程里,CancellationTokenSource`是一个既强大又灵活的工具,能帮助我们管理并取消耗时较长的任务。接下来,我们会详细聊聊它的使用场景、一些推荐的做法,以及实际的例子。
CancellationTokenSource
是 .NET 中用于协作式取消操作的核心类。它允许您:
C#namespace AppCancellation
{
internal class Program
{
private static async Task<string> DownloadWebContentAsync(string url, CancellationToken cancellationToken)
{
using (var client = new HttpClient())
{
try
{
// 设置超时时间
client.Timeout = TimeSpan.FromSeconds(10);
// 发起异步GET请求,并传入取消令牌
var response = await client.GetAsync(url, cancellationToken);
// 确保请求成功
response.EnsureSuccessStatusCode();
// 读取响应内容
return await response.Content.ReadAsStringAsync(cancellationToken);
}
catch (OperationCanceledException)
{
// 捕获操作取消异常
Console.WriteLine("下载已被取消");
return string.Empty;
}
}
}
static async Task Main(string[] args)
{
// 创建取消令牌源
using (var cts = new CancellationTokenSource())
{
// 可以在另一个线程中取消操作
_ = Task.Run(() =>
{
// 例如3秒后取消
Thread.Sleep(3000);
cts.Cancel();
});
try
{
string result = await DownloadWebContentAsync("http://blog.idiosoft.com", cts.Token);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine($"发生错误: {ex.Message}");
}
}
}
}
}
C#namespace AppCancellation
{
internal class Program
{
private static async Task<List<int>> ComputePrimesAsync(int max, CancellationToken cancellationToken)
{
var primes = new List<int>();
for (int i = 2; i <= max; i++)
{
// 定期检查取消状态
cancellationToken.ThrowIfCancellationRequested();
if (IsPrime(i))
{
primes.Add(i);
// 模拟复杂计算
await Task.Delay(10, cancellationToken);
}
}
return primes;
}
// 判断是否为质数的辅助方法
private static bool IsPrime(int number)
{
if (number < 2) return false;
for (int i = 2; i <= Math.Sqrt(number); i++)
{
if (number % i == 0) return false;
}
return true;
}
static async Task Main(string[] args)
{
var cancellationTokenSource = new CancellationTokenSource();
try
{
// 设置超时取消
cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(1));
var result = await ComputePrimesAsync(
10000,
cancellationTokenSource.Token
);
Console.WriteLine($"Computed {result.Count} primes");
}
catch (OperationCanceledException)
{
Console.WriteLine("计算被取消");
}
catch (Exception ex)
{
Console.WriteLine($"发生错误: {ex.Message}");
}
}
}
}
C#namespace AppCancellation
{
internal class Program
{
private static async Task ProcessMultipleTasksAsync()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
var tasks = new List<Task>
{
Task.Run(() => LongRunningTask1(cts.Token)),
Task.Run(() => LongRunningTask2(cts.Token)),
Task.Run(() => LongRunningTask3(cts.Token))
};
await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
Console.WriteLine("某些任务被取消");
}
}
private static async Task LongRunningTask1(CancellationToken token)
{
try
{
for (int i = 0; i < 10; i++)
{
// 模拟耗时操作
await Task.Delay(1000, token);
// 检查是否取消
token.ThrowIfCancellationRequested();
Console.WriteLine($"任务1:第 {i + 1} 次迭代");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("任务1被取消");
throw;
}
}
private static async Task LongRunningTask2(CancellationToken token)
{
try
{
for (int i = 0; i < 10; i++)
{
// 模拟耗时操作
await Task.Delay(1000, token);
// 检查是否取消
token.ThrowIfCancellationRequested();
Console.WriteLine($"任务2:第 {i + 1} 次迭代");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("任务2被取消");
throw;
}
}
private static async Task LongRunningTask3(CancellationToken token)
{
try
{
for (int i = 0; i < 10; i++)
{
// 模拟耗时操作
await Task.Delay(1000, token);
// 检查是否取消
token.ThrowIfCancellationRequested();
Console.WriteLine($"任务3:第 {i + 1} 次迭代");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("任务3被取消");
throw;
}
}
static async Task Main(string[] args)
{
await ProcessMultipleTasksAsync();
}
}
}
C#namespace AppCancellation
{
internal class Program
{
private static async Task ComplexCancellationScenario()
{
using var primaryCts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
using var secondaryCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
// 链接两个 Token
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
primaryCts.Token,
secondaryCts.Token
);
try
{
await LongRunningOperation(linkedCts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("操作被取消");
}
finally
{
linkedCts.Dispose();
}
}
private static async Task LongRunningOperation(CancellationToken cancellationToken)
{
try
{
for (int i = 0; i < 20; i++)
{
// 模拟一个长时间运行的操作
await Task.Delay(1000, cancellationToken);
Console.WriteLine($"正在执行操作,已运行 {i + 1} 秒");
// 检查是否已请求取消
cancellationToken.ThrowIfCancellationRequested();
}
}
catch (TaskCanceledException)
{
Console.WriteLine("任务被取消");
throw;
}
}
static async Task Main(string[] args)
{
await ComplexCancellationScenario();
Console.ReadLine();
}
}
}
using
语句管理 CancellationTokenSource
cancellationToken.IsCancellationRequested
OperationCanceledException
CancellationTokenSource
开销很低OperationCanceledException
CancellationTokenSource
是现代 .NET 异步编程中不可或缺的工具。通过正确使用,可以显著提高应用程序的响应性和资源管理能力。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!