第十节:利用async和await简化异步编程模式的几种写法

一. 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,第二个情况么有线程等待,结果不准确(即共享变量竞用问题)。

 

 

 

posted @   Yaopengfei  阅读(2123)  评论(4编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示