二手车网站源码下载,电销系统多少钱一套,制作免费的网站,汝阳网站建设哪家好目录
前言1. 多线程请求合并数据源2. 对长时间阻塞调用的异步取消令牌应用3. CancellationToken 的链式反应4. CancellationToken 令牌取消的三种方式结束语示例代码下载前言 取消令牌(CancellationToken) 是 .Net Core 中的一项重要功能#xff0c;正确并合理的使用 Cancell…目录
前言1. 多线程请求合并数据源2. 对长时间阻塞调用的异步取消令牌应用3. CancellationToken 的链式反应4. CancellationToken 令牌取消的三种方式结束语示例代码下载前言 取消令牌(CancellationToken) 是 .Net Core 中的一项重要功能正确并合理的使用 CancellationToken 可以让业务达到简化代码、提升服务性能的效果当在业务开发中需要对一些特定的应用场景进行深度干预的时候CancellationToken 将发挥非常重要的作用。
1. 多线程请求合并数据源 在一个很常见的业务场景中比如当请求一个文章详细信息的时候需要同时加载部分点赞用户和评论内容这里一共有 3 个任务如果按照常规的先请求文章信息然后再执行请求点赞和评论那么我们需要逐一的按顺序去数据库中执行 3 次查询但是利用 CancellationToken 我们可以对这 3 个请求同时执行然后在所有数据源都请求完成的时候将这些数据进行合并然后输出到客户端 1.1 合并请求文章信息 public static void Test(){Random rand new Random();CancellationTokenSource cts new CancellationTokenSource();ListTaskArticle tasks new ListTaskArticle();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 个并行任务并把这个任务存入 ListTask 列表对象中在任务开始后马上迭代 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(http://www.weather.com.cn/data/sk/101110101.html, cts.Token);var result await res.Content.ReadAsStringAsync();Console.WriteLine(result);cts.Dispose();client.Dispose();}在上面的代码中首先定义了一个 CancellationTokenSource 对象然后马上发起了一个 HttpClient 的 GetAsync 请求注意这种使用 HttpClient 的方式是不正确的详见我的博客 HttpClient的演进和避坑 在 GetAsync 请求中传入了一个取消令牌然后立即发起了退出请求 Console.WriteLine(result); 不管 3 秒后请求是否返回都将取消令牌等待信号最后输出结果释放资源 注意如果是因为取消令牌退出引起请求中断将会抛出任务取消的异常 TaskCanceledException执行程序输出结果3. CancellationToken 的链式反应 可以使用创建一组令牌通过链接各个令牌使其建立通知关联当 CancellationToken 链中的某个令牌收到取消通知的时候由链式中创建出来的 CancellationToken 令牌也将同时取消 3.1 创建链式测试代码
public async static Task Test(){CancellationTokenSource cts1 new CancellationTokenSource();CancellationTokenSource cts2 new CancellationTokenSource();var cts3 CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);cts1.Token.Register(() {Console.WriteLine(cts1 Canceling);});cts2.Token.Register(() {Console.WriteLine(cts2 Canceling);});cts2.CancelAfter(1000);cts3.Token.Register(() {Console.WriteLine(root Canceling);});var res await new HttpClient().GetAsync(http://www.weather.com.cn/data/sk/101110101.html, cts1.Token);var result await res.Content.ReadAsStringAsync();Console.WriteLine(cts1:{0}, result);var res2 await new HttpClient().GetAsync(http://www.weather.com.cn/data/sk/101110101.html, cts2.Token);var result2 await res2.Content.ReadAsStringAsync();Console.WriteLine(cts2:{0}, result2);var res3 await new HttpClient().GetAsync(http://www.weather.com.cn/data/sk/101110101.html, cts3.Token);var result3 await res2.Content.ReadAsStringAsync();Console.WriteLine(cts3:{0}, result3);}上面的代码定义了 3 个 CancellationTokenSource 分别是 cts1,cts2,cts3每个 CancellationTokenSource 分别注册了 Register 取消回调委托然后使用 HttpClient 发起 3 组网络请求其中设置 cts2 在请求开始 1秒 后退出预期结果为当 cts2 退出后由于 cts3 是使用 CreateLinkedTokenSource(cts1.Token, cts2.Token) 创建出来的所以 cts3 应该也会被取消实际上无论 cts1/cts2 哪个令牌取消cts3 都会被取消 3.2 执行程序输出结果 从上图可以看到红色部分输出结果是首先 cts2 取消接着产生了链式反应导致 cts3 也跟着取消蓝色部分为 cts1 的正常请求结果最后输出了任务退出的异常信息 4. CancellationToken 令牌取消的三种方式 CancellationToken 定义了三种不同的取消方法分别是 Cancel(),CancelAfter(),Dispose()这三种方式都代表了不同的行为方式 4.1 演示取消动作 public static void Test(){CancellationTokenSource cts1 new CancellationTokenSource();cts1.Token.Register(() {Console.WriteLine(\ncts1 ThreadId {0}, System.Threading.Thread.CurrentThread.ManagedThreadId);});cts1.Cancel();Console.WriteLine(cts1 State{0}, cts1.IsCancellationRequested);CancellationTokenSource cts2 new CancellationTokenSource();cts2.Token.Register(() {Console.WriteLine(\ncts2 ThreadId {0}, System.Threading.Thread.CurrentThread.ManagedThreadId);});cts2.CancelAfter(500);System.Threading.Thread.Sleep(1000);Console.WriteLine(cts2 State{0}, cts2.IsCancellationRequested);CancellationTokenSource cts3 new CancellationTokenSource();cts3.Token.Register(() {Console.WriteLine(\ncts3 ThreadId {0}, System.Threading.Thread.CurrentThread.ManagedThreadId);});cts3.Dispose();Console.WriteLine(\ncts3 State{0}, cts3.IsCancellationRequested);}4.2 执行程序输出结果如下 上面的代码定义了 3 个 CancellationTokenSource分别是 cts1/cts2/cts3分别执行了 3 中不同的取消令牌的方式并在取消回调委托中输出线程ID从输出接口中看出当程序执行 cts1.Cancel() 方法后取消令牌立即执行了回调委托并输出线程ID为1cts2.CancelAfter(500) 表示 500ms 后取消为了获得令牌状态这里使线程休眠了 1000ms而 cts3 则直接调用了 Dispose() 方法从输出结果看出cts1 运行在和 Main 方法在同一个线程上线程 ID 都为 1而 cts2 由于使用了延迟取消导致其在内部新创建了一个线程其线程 ID 为 4;最后cts3由于直接调用了 Dispose() 方法但是其 IsCancellationRequested 的值为 False表示未取消而输出结果也表明没有执行回调委托结束语
通过本文我们学习到了如何在不同的应用场景下使用 CancellationToken掌握了合并请求、中断请求、链式反应 三种使用方式最后还了解到三种不同的取消令牌方式知道了各种不同取消方式的区别
示例代码下载
https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.ThreadingDemo