在实际开发中,我们经常需要处理耗时的异步操作,比如网络请求、文件读写等。有时候,我们可能需要取消这些正在进行的异步操作。本文将详细介绍如何在C#中实现异步操作的取消机制。
在开始之前,让我们了解几个重要的概念:
CancellationTokenSource
: 用于发出取消信号的源CancellationToken
: 用于接收取消信号的令牌Task
: 表示异步操作的对象下面是一个完整的示例,展示如何实现可取消的异步操作:
C#using System.Diagnostics;
namespace AppCancellationToken
{
internal class Program
{
// 创建取消令牌源
static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
// 创建HttpClient实例
static readonly HttpClient s_client = new HttpClient
{
MaxResponseContentBufferSize = 1_000_000
};
// 待下载的URL列表
static readonly IEnumerable<string> s_urlList = new string[]
{
"https://learn.microsoft.com",
"https://learn.microsoft.com/dotnet",
"https://learn.microsoft.com/azure",
"https://learn.microsoft.com/visualstudio"
};
static async Task Main()
{
Console.WriteLine("程序启动...");
Console.WriteLine("按回车键取消下载...\n");
// 创建监听取消的任务
Task cancelTask = Task.Run(() =>
{
while (Console.ReadKey().Key != ConsoleKey.Enter)
{
Console.WriteLine("按回车键取消下载...");
}
Console.WriteLine("\n检测到回车键:正在取消下载...\n");
s_cts.Cancel();
});
// 创建下载任务
Task sumPageSizesTask = SumPageSizesAsync();
// 等待任意一个任务完成
Task finishedTask = await Task.WhenAny(cancelTask, sumPageSizesTask);
if (finishedTask == cancelTask)
{
try
{
await sumPageSizesTask;
Console.WriteLine("在处理取消请求之前下载任务已完成。");
}
catch (OperationCanceledException)
{
Console.WriteLine("下载任务已被取消。");
}
}
Console.WriteLine("程序结束。");
}
static async Task SumPageSizesAsync()
{
var stopwatch = Stopwatch.StartNew();
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
stopwatch.Stop();
Console.WriteLine($"\n总计下载字节数: {total:#,#}");
Console.WriteLine($"耗时: {stopwatch.Elapsed}\n");
}
static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
HttpResponseMessage response = await client.GetAsync(url, token);
byte[] content = await response.Content.ReadAsByteArrayAsync(token);
Console.WriteLine($"{url,-60} {content.Length,10:#,#}");
return content.Length;
}
}
}
C#static readonly CancellationTokenSource s_cts = new CancellationTokenSource();
static readonly HttpClient s_client = new HttpClient { MaxResponseContentBufferSize = 1_000_000 };
CancellationTokenSource
实例用于发出取消信号HttpClient
实例用于发送HTTP请求static readonly
确保这些实例在整个应用程序生命周期内只创建一次主方法使用async Task Main()
实现异步入口点,包含两个主要任务:
ProcessUrlAsync
方法实现了单个URL的下载逻辑:
C#static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
HttpResponseMessage response = await client.GetAsync(url, token);
byte[] content = await response.Content.ReadAsByteArrayAsync(token);
Console.WriteLine($"{url,-60} {content.Length,10:#,#}");
return content.Length;
}
GetAsync
方法发送HTTP请求CancellationToken
支持取消操作程序运行后会显示如下输出:
using
语句或字段初始化方式创建CancellationTokenSource
CancellationToken
static readonly
创建长期使用的HTTP客户端实例这种模式适用于需要支持用户取消的长时间运行的异步操作,如网络请求、文件下载等场景。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!