.Net 异步随手记(三)

从《.Net 异步随手记(二)》来看,总感觉还差点儿什么,就是对不同情况的处理。比如当一个 Task 完成了后,我想让它继续执行 T1,如果被取消了就去执行 T2,如果...就去执行 T3,那怎么写呢?

过程是痛苦的,我笨了两天,终于搞通了。之前一直疑惑,为什么引发了 CancellationTokenSource 的 Cancel 方法,捕捉到的 Task 的 IsCanceled 属性依然是 False,今天晚上终于捕捉到了,看来还是自己写的有问题,不废话了,把代码记录一下:

 1 namespace TaskConsole
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             while (true)
 8             {
 9                 var enter = Console.ReadLine();
10
11                 if (enter.ToLower() == "continue")
12                 {
13                     cancelSource = new CancellationTokenSource();
14                     token = cancelSource.Token;
15                     var task = Entry();
16                     Console.WriteLine(task.Status);
17                 }
18                 else if(enter.ToLower() == "cel") {
19                     cancelSource.Cancel();
20                 }
21                 else { break; }
22             }
23         }
24
25
26         async static Task DoWork(string workerName)
27         {
28             int count = 0;
29
30             while (count<10)
31             {
32                 if (token.IsCancellationRequested)
33                 {
34                     Console.WriteLine("用户主动取消了任务");
35                     token.ThrowIfCancellationRequested();
36                 }
37
38                 count++;
39                 Console.WriteLine("{0} count {1} @ Thread Id {2}", workerName, count, System.Threading.Thread.CurrentThread.ManagedThreadId);
40                 await Task.Delay(2000);
41             }
42         }
43
44         async static Task DoCancel(Task callbacker)
45         {
46             //await Task.Delay(2000);
47             Console.WriteLine("Do Cancel 任务运行了");
48         }
49
50         async static Task DoContinue(Task callbacker)
51         {
52             //await Task.Delay(1000);
53             //Console.WriteLine("Continue 任务运行了 @ Task is {1}", callbacker.Status);
54             Console.WriteLine("Do Continue 运行了");
55         }
56
57         async static Task Entry()
58         {
59             {
60                 var taskWorker = Task.Factory.StartNew(() => DoWork("工作者1"));
61                 try
62                 {
63                     await taskWorker.Result;
64                     Console.WriteLine("taskworker 已经完成,是被取消的? {0}", taskWorker.Result.IsCanceled);
65                 }
66                 catch (OperationCanceledException)
67                 {
68                     Console.WriteLine("OperationCanceledException 异常,任务是被取消的? {0}", taskWorker.Result.IsCanceled);
69                 }
70
71                 var c1 = taskWorker.Result.ContinueWith(backer => DoCancel(backer), TaskContinuationOptions.OnlyOnCanceled);
72                 var c2 = taskWorker.Result.ContinueWith(backer => DoContinue(backer), TaskContinuationOptions.OnlyOnRanToCompletion);
73             }
74         }
75
76         static CancellationTokenSource cancelSource;
77         static CancellationToken token;
78     }
79 }

从代码可以看出,C1 = 的是 taskWorker 的 Result 的 ContinueWith,也就是说,Token 真正引发的取消操作是作用于 DoWork 方法内的,而 taskWorker 并不是 DoWork 这个异步方法的引用,而是被 Factory“创建出来的某个运行 DoWork 的 Task”。因此,想要 C1、C2起作用,必须侦测的是 DoWork 方法到底是完成了还是被取消了,而 DoWork 方法是 taskWorker 的 Result,因此代码写成这样,运行结果就正确了。

输入 continue 启动程序,如果正常执行结束,将会是这样

中途输入 cel 来手动取消,将会是这样

感谢自己这脑袋终于想明白了,总结,如果写的是

1 var c1 = taskWorker.ContinueWith(backer => DoCancel(backer), TaskContinuationOptions.OnlyOnCanceled);
2 var c2 = taskWorkert.ContinueWith(backer => DoContinue(backer), TaskContinuationOptions.OnlyOnRanToCompletion);

那 C1 就永远不会有机会运行了,因为无论 DoWork 是正常结束还是被取消了,被工厂创建出来的那个 Task (也就是 taskWorker 所指向的对象)在 DoWork 返回之后都是 RanToCompletion。

时间: 2024-12-19 18:09:18

.Net 异步随手记(三)的相关文章

.Net 异步随手记(一)

今天要记录的内容摘要是: 什么时候异步代码能“等”在那里,什么时候不会“等” 这两天Coding的时候碰到一个事儿,就是想让异步等在那里结果却直接执行过去了,比如这样: 1 async static void Count() 2 { 3 Console.WriteLine("Task Void 开始"); 4 Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 5 int count = 0; 6 while (count

Android笔记(三十一) Android中的异步更新(三) Handler (二)

先看简单示例:点击按钮,2s之后,TextView改变内容. package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.Te

.Net 异步随手记(二)

Task.ContinueWith 这货,和 await 一样有“陷阱”.^^,因为写 ContinueWith 不能直观如人的“过程性”思维,写在 ContinueWith 括号里的部分不一定只在发起 ContinueWith 的任务完成后完成,比如这样: 1 namespace TaskConsole 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 while (true) 8 { 9 var enter = C

ELK菜鸟手记 (三) - X-Pack权限控制之给Kibana加上登录控制以及index_not_found_exception问题解决

0. 背景 我们在使用ELK进行日志记录的时候,通过网址在Kibana中查看我们的应用程序(eg: Java Web)记录的日志, 但是默认是任何客户端都可以访问Kibana的, 这样就会造成很不安全,我们应该设置相应的用户名和密码, 只有通过登录用户名和密码才能通过Kibana查看我们的日志. 1. 在elasticsearch 2.x的版本是怎么做的 笔者网上查了一些博文,大部分推荐的是通过给elasticsearch安装Shield插件,参考链接如下: http://blog.csdn.n

android 的异步任务

/** * 异步任务的三个泛型参数: * 1.调用execute方法时传入的参数类型,输入参数 * 2.progressUpdate的方法入参 * 3.异步任务的返回结果类型 doInBackground的返回类型,doPostExecute的方法入参 * * 使用异步任务的一些注意事项 * 1.一个异步任务只能执行一次,多次执行的话,则会跑出异常 * 2.必须在UI线程中创建异步任务示例 * 3.必须在UI线程中调用execute方法 */ public class AsyncTaskTest

Javascript异步编程之setTimeout与setInterval详解分析(一)

Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程( 注意: 特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛多多原谅!) 1. setTimeout与setInterval详细分析基本原理. 接下来这篇博客会总结setTimeout和setInterval基本点,对于上面三点会分三篇博客分别来总结,对于知道上面三点的人,但是又不是非常了解全面知识点的码农来说,没有关系的,我们可以慢慢来学习,来理解,或

JavaScript及其异步实现

由于javascript本身是单线程模型,这里主要通过Callbacks,Listeners,Control Flow Libraries ,Promises四种方式来实现异步操作. Reference:            1.JavaScript异步编程的四种方法(转)           2.JavaScript Promises 一.Callbacks(函数回调) 让我们首先以函数回调方式来开头,这种方式也是最基本,同时也是大家都知道的异步实现方法. 现在我们有两个函数:Functio

异步编程、线程和任务

用鼠标操作,我们习惯了延迟,过去几十年都是这样.有了触摸UI,应用程序要求立刻响应用户的请求. C#5.0提供了更强大的异步编程,仅添加了两个新的关键字:async和await. 使用异步编程,方法调用是在后头运行(通常在线程和任务的帮助下),并且不会阻塞调用线程. => 所以 异步编程应该就是使用线程和任务进行编程. 另外,异步委托也是在线程和任务的帮助下完成的,它是基于事件的异步模式. 1.首先先了解一个概念:(WPF的,应该和WindowsForm差不多) 在WindowsForm和WPF

两种高效的并发模式(半同步/半异步和领导者/追随者)

一.并发编程与并发模式 并发编程主要是为了让程序同时执行多个任务,并发编程对计算精密型没有优势,反而由于任务的切换使得效率变低.如果程序是IO精密型的,则由于IO操作远没有CPU的计算速度快,所以让程序阻塞于IO操作将浪费大量的CPU时间.如果程序有多个线程,则当前被IO操作阻塞的线程可主动放弃CPU,将执行权转给其它线程.(*IO精密型和cpu精密型可以参考此文:CPU-bound(计算密集型) 和I/O bound(I/O密集型)) 并发编程主要有多线程和多进程,这里我们先讨论并发模式,并发