Asp.Net Core 轻松学-多线程之取消令牌

 

前言

    取消令牌(CancellationToken) 是 .Net Core 中的一项重要功能,正确并合理的使用 CancellationToken 可以让业务达到简化代码、提升服务性能的效果;当在业务开发中,需要对一些特定的应用场景进行深度干预的时候,CancellationToken 将发挥非常重要的作用。

1. 多线程请求合并数据源

在一个很常见的业务场景中,比如当请求一个文章详细信息的时候,需要同时加载部分点赞用户和评论内容,这里一共有 3 个任务,如果按照常规的先请求文章信息,然后再执行请求点赞和评论,那么我们需要逐一的按顺序去数据库中执行 3 次查询;但是利用 CancellationToken ,我们可以对这 3 个请求同时执行,然后在所有数据源都请求完成的时候,将这些数据进行合并,然后输出到客户端

1.1 合并请求文章信息
       public static void Test()         {             Random rand = new Random();             CancellationTokenSource cts = new CancellationTokenSource();             List<Task<Article>> tasks = new List<Task<Article>>();             TaskFactory factory = new TaskFactory(cts.Token);             foreach (var t in new string[] { "Article", "Post", "Love" })             {                 Console.WriteLine("开始请求");                 tasks.Add(factory.StartNew(() =>                             {                                 var article = new Article { Type = t };                                 if (t == "Article")                                 {                                     article.Data.Add("文章已加载");                                 }                                 else                                 {                                     for (int i = 1; i < 5; i++)                                     {                                         Thread.Sleep(rand.Next(1000, 2000));                                         Console.WriteLine("load:{0}", t);                                         article.Data.Add($"{t}_{i}");                                     }                                 }                                 return article;                             }, cts.Token));             }              Console.WriteLine("开始合并结果");             foreach (var task in tasks)             {                 Console.WriteLine();                 var result = task.Result;                 foreach (var d in result.Data)                 {                     Console.WriteLine("{0}:{1}", result.Type, d);                 }                 task.Dispose();             }              cts.Cancel();             cts.Dispose();             Console.WriteLine("\nIsCancellationRequested:{0}", cts.IsCancellationRequested);         }

上面的代码定义了一个 Test() 方法,在方法内部,首先定义了一个 CancellationTokenSource 对象,该退出令牌源内部创建了一个取消令牌属性 Token ;接下来,使用 TaskFacory 任务工厂创建了 3 个并行任务,并把这个任务存入 List<Task> 列表对象中,在任务开始后,马上迭代 tasks 列表,通过同步获取每个任务的执行 Result 结果,在取消令牌没有收到取消通知的时候,任务将正常的执行下去,在所有任务都执行完成后,将 3 个请求结果输出到控制台中,同时销毁任务释放线程资源;最后,执行 cts.Cancel()取消令牌并释放资源,最后一句代码将输出令牌的状态。

1.2 执行程序,输出结果

通过上面的输出接口,可以看出,红色部分是模拟请求,这个请求时多线程进行的,Post 和 Love 交替出现,是因为在程序中通过线程休眠的方式模拟网络阻塞过程,蓝色为合并结果部分,可以看到,虽然“文章信息”已经加载完成,但是因为 Post 和 Love 还在请求中,由于取消令牌未收到退出通知,所以合并结果会等待信号,在所有线程都执行完成后,通过 cts.Cancel() 通知令牌取消,所有事件执行完成,控制台打印结果黄色部分为令牌状态,显示为 True ,令牌已取消。

2. 对长时间阻塞调用的异步取消令牌应用

在某些场景中,我们需要请求外部的第三方资源,比如请求天气预报信息;但是,由于网络等原因,可能会造成长时间的等待以致业务超时退出,这种情况可以使用 CancellationToken 来进行优化,但请求超过指定时长后退出,而不必针对每个 HttpClient 进行单独的超时设置

2.1 获取天气预报
        public async static Task GetToday()         {             CancellationTokenSource cts = new CancellationTokenSource();             cts.CancelAfter(3000);             HttpClient client = new HttpClient();             var res = await client.GetAsync("upload/201812281612595750.png" style="margin: 0px; padding: 0px; border: 5px solid rgb(204, 204, 204); border-radius: 5px 0px; box-shadow: darkgrey 10px 10px 30px 5px; max-width: 900px; height: auto; width: auto;" alt="" />

3. CancellationToken 的链式反应

可以使用创建一组令牌,通过链接各个令牌,使其建立通知关联,当 CancellationToken 链中的某个令牌收到取消通知的时候,由链式中创建出来的 CancellationToken 令牌也将同时取消

3.1 创建链式测试代码
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信