请选择 进入手机版 | 继续访问电脑版

[ASP.NET] .Net中异步任务 的取消和监控的详细 实现

[复制链接]
查看52 | 回复10 | 2021-9-15 06:36:21 | 显示全部楼层 |阅读模式
目次

干系 范例 :

  • CancellationTokenSource 紧张 用来创建或取消令牌
  • CancellationToken 监听令牌状态,注册令牌取消变乱
  • OperationCanceledException 令牌被取消时抛出的非常 ,可以由监听者自主决定是否抛出非常

CancellationTokenSource

创建令牌:

  1. CancellationTokenSource cts = new CancellationTokenSource()
  2. CancellationToken token=cts.Token;
复制代码

取消开释 令牌:

  1. cts.Cancel();
复制代码

CancellationToken

监听令牌取消变乱 :

  1. token.Register(() => Console.WriteLine("令牌被取消"));
复制代码

判断 令牌是否取消

  1. //返回一个bool,如果令牌被取消为true
  2. token.IsCancellationRequested
  3. //如果token被取消则抛出异常,内部实现其实就是判断IsCancellationRequested
  4. token.ThrowIfCancellationRequested()=>{
  5. if(token.IsCancellationRequested){
  6. throw new OperationCanceledException();
  7. }
  8. }
复制代码

代码示例

下面模拟 一个文件下载的使命 ,在未下载完成后下载使命 被取消

  1. public void Run()
  2. {
  3. CancellationTokenSource cts = new CancellationTokenSource();
  4. Task.Run(() =>
  5. {
  6. //等待两秒后取消,模拟的是用户主动取消下载任务
  7. Thread.Sleep(2000);
  8. cts.Cancel();
  9. });
  10. try
  11. {
  12. var size = DownloadFile(cts.Token);
  13. Console.WriteLine("文件大小:" + size);
  14. }
  15. catch (OperationCanceledException)
  16. {
  17. Console.WriteLine("下载失败");
  18. }finally{
  19. cts.Dispose();
  20. }
  21. Thread.Sleep(2000);
  22. }
  23. /// <summary>
  24. /// 模拟下载文件,下载文件需要五秒
  25. /// </summary>
  26. /// <returns></returns>
  27. public int DownloadFile(CancellationToken token)
  28. {
  29. token.Register(() =>
  30. {
  31. System.Console.WriteLine("监听到取消事件");
  32. });
  33. Console.WriteLine("开始下载文件");
  34. for (int i = 0; i < 5; i++)
  35. {
  36. token.ThrowIfCancellationRequested();
  37. Console.WriteLine(i.ToString());
  38. Thread.Sleep(1000);
  39. }
  40. Console.WriteLine("文件下载完成");
  41. return 100;
  42. }
复制代码

输出效果 :

  1. 开始下载文件
  2. 0
  3. 1
  4. 监听到取消事件
  5. 下载失败
复制代码

思考

为什么要将CancellationToken和CancellationTokenSource分为两个类呢,直接一个CancellationToken又可以取消又可以判断 状态注册啥的不是更好,更方便?

着实 每种类的计划 和实现都可以有很多不同的策略,CTS和CT从这个两个类提供的为数不多的公开方法中就可以看出,CTS用来控制Token的天生 和取消等生命周期状态,CT只能用来监听和判断 ,无法对Token的状态举行 改变。

以是 这种计划 的目标 就是关注点分离。限定 了CT的功能,避免Token在传递过程中被不可控的因素取消造成混乱。

关联令牌

继续拿上面的示例来说,示例中实现了从外部控制文件下载功能的停止 。

假如 要给文件下载功能加一个超时时间的限定 ,此时可以增长 一个控制超时时间的token,将外部传来的token和内部token 关联起来变为一个token

只必要 将DownloadFile()函数做如下改造即可

  1. public int DownloadFile(CancellationToken externalToken)
  2. {
  3. //通过构造函数设置TokenSource一秒之后调用Cancel()函数
  4. var timeOutToken = new CancellationTokenSource(new TimeSpan(0, 0, 1)).Token;
  5. using (var linkToken = CancellationTokenSource.CreateLinkedTokenSource(externalToken, timeOutToken))
  6. {
  7. Console.WriteLine("开始下载文件");
  8. for (int i = 0; i < 5; i++)
  9. {
  10. linkToken.Token.ThrowIfCancellationRequested();
  11. Console.WriteLine(i.ToString());
  12. Thread.Sleep(1000);
  13. }
  14. Console.WriteLine("文件下载完成");
  15. return 100;
  16. }
  17. }
复制代码

此时不论是externalToken取消,或是timeOutToken取消,都会触发linkToken的取消变乱

CancellationChangeToken

CancellationChangeToken紧张 用来监测目标 变化,需共同 ChangeToken使用 。从功能场景来说,着实 ChangeToken的功能和变乱 好像 差不多,当监控的目标 发生了变化,监听者去做一系列的变乱 。

但是变乱 的话,监听者必要 知道目标 的存在,就是假如 A要注册B的变乱 ,A是要依靠 B的。

CancellationChangeToken是基于CancellationToken来实现的,可以做到依靠 于Token而不直接依靠 被监听的类

创建CancellationChangeToken:

  1. new CancellationChangeToken(new CancellationTokenSource().Token)
复制代码

监听Token变动

  1. new CancellationChangeToken(cts.Token).RegisterChangeCallback(obj => Console.WriteLine("token 变动"), null);
复制代码

CancellationChangeToken只是把CancellationToken包装了一层。RegisterChangeCallback终极 也是监听的CancellationToken的IsCancellationRequested状态。

以是 就有个题目 ,代码写到这里,并不能实现每次内部变动都触发回调变乱 。

由于 CT只会Cancel一次,对应的监听也会实行 一次。无法实现多次监听

为了实现变化的持续监听,必要 做两个操作

  • 让Token在Cancel之后重新初始化
  • 每次Cancel回调之后重新监听新的Token

先上代码,下面的代码实现了每次时间变动都会关照 展示面板革新 时间的表现

  1. public void Run()
  2. {
  3. var bjDate = new BeijingDate();
  4. DisplayDate(bjDate.GetChangeToken, bjDate.GetDate);
  5. Thread.Sleep(50000);
  6. }
  7. public void DisplayDate(Func<IChangeToken> getChangeToken, Func<DateTime> getDate)
  8. {
  9. ChangeToken.OnChange(getChangeToken, () => Console.WriteLine("当前时间:" + getDate()));
  10. }
  11. public class BeijingDate
  12. {
  13. private CancellationTokenSource cts;
  14. private DateTime date;
  15. public BeijingDate()
  16. {
  17. cts = new CancellationTokenSource();
  18. var timer = new Timer(TimeChange, null, 0, 1000);
  19. }
  20. private void TimeChange(object state)
  21. {
  22. date = DateTime.Now;
  23. var old = cts;
  24. cts = new CancellationTokenSource();
  25. old.Cancel();
  26. }
  27. public DateTime GetDate() => date;
  28. public CancellationChangeToken GetChangeToken()
  29. {
  30. return new CancellationChangeToken(cts.Token);
  31. }
  32. }
复制代码

在TimeChange()中修改了时间,重置了Token并将旧的Token取消

在DisplayDate中用ChangeToken.OnChange获取对应的Token并监听

实现了DisplayData函数和BeijingDate这个类的解耦

ChangeToken.OnChange 这个函数吸取 两个参数,一个是获取Token的委托,一个是Token取消变乱 的相应 委托。

每次在处理完Token的取消变乱 后,他会重新调用第一个委托获取Token,而此时我们已经天生 了新的Token,终极 实现了持续监控

到此这篇关于.Net中异步使命 的取消和监控的文章就先容 到这了,更多干系 .Net中异步使命 的取消和监控内容请搜刮 脚本之家从前 的文章或继续欣赏 下面的干系 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

avatar wangliqxm | 2021-9-29 09:21:49 | 显示全部楼层
楼上的别说的那么悲观好吧!
回复

使用道具 举报

avatar 大嘴997 | 2021-9-29 09:25:30 | 显示全部楼层
我只看看不说话。。。
回复

使用道具 举报

avatar 123457227 | 2021-9-29 10:39:56 | 显示全部楼层
看了这么多帖子,第一次看到这么有深度了!
回复

使用道具 举报

avatar 123457191 | 2021-10-10 06:30:49 | 显示全部楼层
关注一下!
回复

使用道具 举报

avatar xinting_6ym | 2021-10-11 15:35:36 | 显示全部楼层
admin楼主人气很旺!
回复

使用道具 举报

avatar 123457608 | 2021-10-13 15:44:50 | 显示全部楼层
楼上的刚出院吧?
回复

使用道具 举报

admin楼主会死的很有节奏的!
回复

使用道具 举报

admin楼主练了葵花宝典吧?
回复

使用道具 举报

avatar 素身素 | 前天 22:24 | 显示全部楼层
顶一下,收藏了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则