.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 < 10)
 7             {
 8                 Console.WriteLine("Print value:{0}", count);
 9                 count++;
10                 await Task.Delay(500);
11             }
12             Console.WriteLine("Task Void 结束");
13         }

 

接下来写这两句:

1 var taskVoid = new Task(Count);
2 await taskVoid;

 

哈哈,原本按照其它异步方式去写的时候比如 await HttpClient.GetAsync(); 是非常正常的,程序的逻辑会停在这一句,直到获得结果才会进行下面的语句。但运行 await taskVoid 后,会立即运行下面的语句,这是怎么回事?经过仔细检查发现是因为 Count 方法没有返回值,是 void ,因此必须要加以改造。如果 Count 方法返回值是 Task ,await 才能起效,比如改成这样:

 1         static void Main(string[] args)
 2         {
 3             Entry();
 4             Console.ReadLine();
 5             
 6         }
 7 
 8         async static Task CountAsync()
 9         {
10             Console.WriteLine("Task Void 开始");
11             int count = 0;
12             while (count < 10)
13             {
14                 Console.WriteLine("Print value:{0}", count);
15                 count++;
16                 await Task.Delay(500);
17             }
18             Console.WriteLine("Task Void 结束");
19         }
20 
21         async static void Entry()
22         {
23             // 创建一个无参数无返回值的方法
24             var taskVoid = Task.Factory.StartNew(CountAsync);
25 
26             await taskVoid.Result;
27             // 创建一个 taskVoid 之后才能运行的方法
28             var taskContinue = taskVoid.ContinueWith(async (t) =>
29             {
30 
31                 Console.WriteLine("这是在 TaskVoid 运行之后才能运行的 TaskContinue,Task void 的状态是 {0}", t.Status);
32                 await Task.Delay(1000);
33             });
34             ;
35         }
改造后的异步

 

个人理解:

await 作为语法糖,起作用的对象是 Task ,void 方法返回的不是 Task 自然对之前的写法来讲不起作用。Task 用一个“新线程” 去执行 void 方法,自然立即就“返回”了,但返回并不表示方法结束了,方法内还是按照自己的逻辑去运行了,所以这个时候我只能眼巴巴看着 void 类型的 Count 返回却无力控制它。改成后面的写法之后,改造后的 CountAsync 方法返回的是 Task,意思是告诉上层“我是一个Task”,这个时候 await 就可以起作用了。但直接写 await taskVoid 依旧不能起作用,因为此时 taskVoid 无返回值,也就是立即返回了,所以必须要写成“var taskVoid = Task.Factory.StartNew(CountAsync)” + "await taskVoid.Result"的方式,StartNew 方法会内部新建一个 Task 并返回,这个 Task 的返回值是 CountAsync,而 Result 表示了“我要等待运行 CountAsync 这个异步任务的异步任务的结果返回来”。因此,await 起了作用,执行顺序正确了。

本人学艺不精,对 .Net 内部基本没什么涉猎,如有老鸟看到希望能提出指正意见,谢谢。

posted @ 2016-08-11 16:51  试试手气  阅读(256)  评论(0编辑  收藏  举报