编辑
2025-10-15
C#
00

目录

前置条件
核心概念
完整示例代码
代码详解
初始化设置
主方法实现
异步下载实现
运行效果
注意
总结

在实际开发中,我们经常需要处理耗时的异步操作,比如网络请求、文件读写等。有时候,我们可能需要取消这些正在进行的异步操作。本文将详细介绍如何在C#中实现异步操作的取消机制。

前置条件

  • .NET 5.0或更高版本
  • Visual Studio或Visual Studio Code
  • 基本的C#异步编程知识

核心概念

在开始之前,让我们了解几个重要的概念:

  1. CancellationTokenSource: 用于发出取消信号的源
  2. CancellationToken: 用于接收取消信号的令牌
  3. 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()实现异步入口点,包含两个主要任务:

  1. 取消监听任务(cancelTask)
  2. 下载处理任务(sumPageSizesTask)

异步下载实现

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支持取消操作
  • 返回下载内容的字节数

运行效果

程序运行后会显示如下输出:

image.png

注意

  1. 始终使用using语句或字段初始化方式创建CancellationTokenSource
  2. 在所有可取消的异步操作中传递CancellationToken
  3. 正确处理取消异常
  4. 使用static readonly创建长期使用的HTTP客户端实例

总结

这种模式适用于需要支持用户取消的长时间运行的异步操作,如网络请求、文件下载等场景。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!