首页 > 技术文章 > 第十节:利用async和await简化异步编程模式的几种写法

yaopengfei 2018-01-14 18:51 原文

一. async和await简介

PS:简介

1. async和await这两个关键字是为了简化异步编程模型而诞生的,使的异步编程跟简洁,它本身并不创建新线程,但在该方法内部开启多线程,则另算。

2. 这两个关键字适用于处理一些文件IO操作。

3. 好处:代码简介,把异步的代码写成了同步的形式,提高了开发效率。

 坏处:如果使用同步思维去理解,容易出问题,返回值对不上。

 

二. 几种用法

情况1:当只有async,没有await时,方法会有个警告,和普通的多线程方法没有什么区别,不存在线程等待的问题。

代码实践:

 1  private static async void Test1()
 2         {
 3             //主线程执行
 4             Console.WriteLine("主线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
 5             //启动新线程完成任务
 6             Task task = Task.Run(() =>
 7             {
 8                 Console.WriteLine("子线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
 9                 Thread.Sleep(3000);
10                 Console.WriteLine("子线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
11             });
12             //主线程执行
13             Console.WriteLine("主线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
14         }

代码结果:

情况2:不推荐void返回值,使用Task来代替Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用,async Void 不行。

代码实践:

 1         /// <summary>
 2         /// 不推荐void返回值,使用Task来代替
 3         /// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。async Void 不行
 4         /// </summary>
 5         private static async void Test2()
 6         {
 7             //主线程执行
 8             Console.WriteLine("主线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
 9             //启动新线程完成任务
10             Task task = Task.Run(() =>
11             {
12                 Console.WriteLine("子线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
13                 Thread.Sleep(3000);
14                 Console.WriteLine("子线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
15             });
16             await task;   //等待子线程执行完毕,方可执行后面的语句
17             Console.WriteLine("主线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
18         }

代码结果:

 

情况3:async Task == async void。 区别:Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用,async Void 不行。

代码实践:

 1          /// <summary>
 2         /// 无返回值  async Task == async void
 3         /// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用,async Void 不行
 4         /// </summary>
 5         private static async Task Test3()
 6         {
 7             //主线程执行
 8             Console.WriteLine("主线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
 9             //启动新线程完成任务
10             Task task = Task.Run(() =>
11             {
12                 Console.WriteLine("子线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
13                 Thread.Sleep(3000);
14                 Console.WriteLine("子线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
15             });
16             await task;   //等待子线程执行完毕,方可执行后面的语句
17             Console.WriteLine("主线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
18         }

 

代码结果:

 

情况4和情况5:说明要使用子线程中的变量,一定要等子线程执行结束后再使用。

代码实践:

 

 1         /// <summary>
 2         /// 带返回值的Task,要使用返回值,一定要等子线程计算完毕才行
 3         /// </summary>
 4         /// <returns></returns>
 5         private static async Task<long> Test4()
 6         {
 7             //主线程执行
 8             Console.WriteLine("主线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
 9             long result = 0;
10             //启动新线程完成任务
11             Task task = Task.Run(() =>
12             {
13                 for (long i = 0; i < 100; i++)
14                 {
15                     result += i;
16                 }
17             });
18             await task;   //等待子线程执行完毕,方可执行后面的语句
19             Console.WriteLine("主线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
20             Console.WriteLine("result:{0}", result);
21             return result;
22         }

 

 1         /// <summary>
 2         /// 带返回值的Task,要使用返回值,一定要等子线程计算完毕才行
 3         /// 与情况四形成对比,没有等待,最终结果不准确
 4         /// </summary>
 5         /// <returns></returns>
 6         private static Task<long> Test5()
 7         {
 8             //主线程执行
 9             Console.WriteLine("主线程{0}开始:", Thread.CurrentThread.ManagedThreadId);
10             long result = 0;
11             //启动新线程完成任务
12             TaskFactory taskFactory = new TaskFactory();
13             Task<long> task = taskFactory.StartNew<long>(() =>
14             {
15                 for (long i = 0; i < 100; i++)
16                 {
17                     result += i;
18                 }
19                 return 1;
20             });
21             Console.WriteLine("主线程{0}结束:", Thread.CurrentThread.ManagedThreadId);
22             Console.WriteLine("result:{0}", result);
23             return task;
24         }

代码结果:

   以上两种情况,第一种情况含有线程等待的结果为4950,第二个情况么有线程等待,结果不准确(即共享变量竞用问题)。

 

 

 

推荐阅读