C#中使用 CancellationToken 取消异步任务

.NET 提供了一个类方便用来发出操作取消的信号,这个类就是CancellationToken,它的好处在于它可以在任意数量的线程之间、线程池任务之间、Task之间传递信号,并且所需的代码很简单。通常用于下载超时中断、用户取消任务等情况。

CancellationToken 通常搭配 CancellationTokenSource 使用,后者是前者的一个管理类,使用 CancellationTokenSource 的 Token 属性,可以获取CancellationToken,并控制信号的发送。这两个类都属于命名空间 System.Threading

在异步编程中,只需将 Token 作为一个参数传入异步方法中。在异步方法外便能通过 CancellationTokenSource.Cancel 方法发出取消信号或者 CancelAfter 方法在一段时间后发出取消信号,这会改变 Token 的 isCancellationRequested 属性。在异步方法内,通过这个属性获取取消信号,并作出对应的处理操作。

一、定时取消任务

代码示例:

 1 using System;
 2 using System.Threading.Tasks;
 3 using System.Threading;
 4 using System.Net.Http;
 5 
 6 namespace CancellationTokenTest
 7 {
 8     class Program
 9     {
10         static async Task Main(string[] args)
11         {
12             CancellationTokenSource cts = new CancellationTokenSource();
13             //cts.Cancel() //立即发出取消信号
14             //3秒后发出取消信号,模拟取消行为
15             cts.CancelAfter(3000);
16             Console.WriteLine("下载开始");
17             await DownloadAsync(cts.Token);
18             Console.ReadKey();
19         }
20 
21         static async Task DownloadAsync(CancellationToken ct)
22         {
23             using (HttpClient client = new HttpClient())
24             {
25                 //模拟一个比较耗时的下载的过程
26                 for (int i = 0; i < 1000; i++)
27                 {
28                     string s = await client.GetStringAsync("https://www.baidu.com");
29                     Console.WriteLine(s);
30 
31                     //ct.ThrowIfCancellationRequested();//直接抛出异常
32                     //判断是否需要取消,并自行处理
33                     if (ct.IsCancellationRequested)
34                     {
35                         Console.WriteLine("下载取消");
36                         break;
37                     }
38                 }
39                 
40             }
41         }
42 
43     }
44 }

3秒之后,任务将自动取消。

二、手动取消任务

手动调用 cts.Cancel() 来取消任务

 1  
 2 static async Task Main(string[] args)
 3 {
 4     async Task Execute(CancellationToken token)
 5     {
 6         await Task.Delay(3000, token);
 7         Console.WriteLine("Executed");
 8     } 
 9  
10     CancellationTokenSource cts = new CancellationTokenSource();  
11  
12     _ = Execute(cts.Token);
13  
14     // 手动取消任务
15     cts.Cancel();  
16  
17     Console.ReadKey();
18 }

三、CancellationToken 注册回调

们可以调用 Register()方法,注册Token取消的回调,参数需要传入 Action 委托。

  CancellationTokenSource cts = new CancellationTokenSource(1000);
 
cts.Token.Register(() => Console.WriteLine("任务已取消!"));
 
// 开始异步任务
_ = Execute(cts.Token);    
 
Console.ReadKey();

Register() 注册回调后,返回一个 CancellationTokenRegistration 对象,同样的,你可以在回调函数执行前,移除注册回调,就像这样:

cts.Token.Register(() => Console.WriteLine("任务已取消!")).Unregister();

 

posted @ 2023-01-25 23:08  ziff123  阅读(2236)  评论(0编辑  收藏  举报