一篇文章弄懂C#中的async和await

作者:痴者工良 时间:2021-08-15 16:41:14 

目录
  • 前言

    • async

    • await

  • 从以往知识推导

    • 创建异步任务

    • 创建异步任务并返回Task

    • 异步改同步

    • 说说 await Task

    • 说说 async Task<TResult>

    • 同步异步?

    • Task封装异步任务

    • 关于跳到 await 变异步

    • 为什么出现一层层的 await

  • 总结

    前言

    本文介绍async/Task。在学习该知识点过程中,一定要按照每一个示例,去写代码、执行、输出结果,自己尝试分析思路。

    async

    微软文档:使用 async 修饰符可将方法、lambda 表达式或匿名方法指定为异步。

    使用 async 修饰的方法,称为异步方法。

    例如:

    为了命名规范,使用 async 修饰的方法,需要在方法名称后面加上 Async 。


    public async Task<int> TestAsync()  
    {  
       // . . . .  
    }
    Lambda :

    static void Main()
           {
               Thread thread = new Thread(async () =>
               {
                   await Task.Delay(0);
               });
           }
           public static async Task<int> TestAsync() => 666;

    await

    微软文档:await 运算符暂停对其所属的 async 方法的求值,直到其操作数表示的异步操作完成。

    异步操作完成后,await 运算符将返回操作的结果(如果有)。

    好的,到此为止,async 和 await ,在官方文档中的说明,就这么多。

    从以往知识推导

    这里我们不参考文档和书籍的资料,不要看文档和书籍中的示例,我们要一步步来从任务(Task)中的同步异步开始,慢慢摸索。去分析 async 和 await 两个关键字给我们的异步编程带来了什么样的便利。

    创建异步任务

    场景:周六日放假了,可以打王者(一种游戏),但是昨天的衣服还没有洗;于是用洗衣机洗衣服,清洗期间,开一局王者(一种游戏)。

    我们可以编写一个方法如下:


           static void Main()
           {
               Console.WriteLine("准备洗衣服");

    // 创建一个洗衣服的任务
               Task<int> task = new Task<int>(() =>
               {
                   // 模拟洗衣服的时间
                   int time = new Random().Next(2, 6);
                   Thread.Sleep(TimeSpan.FromSeconds(time));
                   return time;
               });

    Console.WriteLine("开始洗衣服");

    // 让洗衣机洗衣服
               task.Start();

    Console.WriteLine("我去打王者,让洗衣机洗衣服");
               // 打王者
               Thread.Sleep(TimeSpan.FromSeconds(4));
               Console.WriteLine("打完王者了,衣服洗完了嘛?");

    Console.WriteLine(task.IsCompleted);
               if (task.IsCompleted)
                   Console.WriteLine("洗衣服花的时间:" + task.Result);
               else
               {
                   Console.WriteLine("在等洗衣机洗完衣服");
                   task.Wait();
                   Console.WriteLine("洗衣服花的时间:" + task.Result);
               }
               Console.WriteLine("洗完了,捞出衣服,晒衣服,继续打王者去");
           }

    创建异步任务并返回Task

    上面的示例,虽然说,异步完成了一个任务,但是这样,将代码都放到 Main ,可读性十分差,还要其它什么规范之类的,不允许我们写这样的垃圾代码。于是我们将洗衣服这个任务,封装到一个方法中,然后返回 Task 即可。

    在 Program 类中,加入如下一个方法,这个方法用于执行异步任务,并且返回 Task 对象。


           /// <summary>
           /// 执行一个任务
           /// </summary>
           /// <returns></returns>
           public static Task<int> TestAsync()
           {
               Task<int> task = new Task<int>(() =>
               {
                   // 模拟洗衣服的时间
                   int time = new Random().Next(2, 6);
                   Thread.Sleep(TimeSpan.FromSeconds(time));
                   return time;
               });
               task.Start();
               return task;
           }

    Main 方法中,改成


           static void Main()
           {
               Console.WriteLine("准备洗衣服");

    // 创建一个洗衣服的任务
               Task<int> task = TestAsync();
               ... ...

    但是,两者差别还是不大。

    异步改同步

    我们创建了异步方法,去执行一个洗衣服的任务;当打完游戏后,需要检查任务是否完成,然后才能进行下一步操作,这时候就出现了 同步。为了保持同步和获得执行结果,我们使用了 .Wait() 、.Result 。

    这里我们尝试将上面的操作转为同步,并且获得执行结果。


       class Program
       {
           static void Main()
           {
               int time = Test();
               // ... ...
           }

    /// <summary>
           /// 执行一个任务
           /// </summary>
           /// <returns></returns>
           public static int Test()
           {
               Task<int> task = new Task<int>(() =>
               {
                   // 模拟洗衣服的时间
                   int time = new Random().Next(2, 6);
                   Thread.Sleep(TimeSpan.FromSeconds(time));
                   return time;
               });
               task.Start();
               return task.Result;
           }
       }

    说说 await Task

    Task 和 Task<TResult> ,前者是一个没有返回结果的任务,后者是有返回结果的任务。前面的文章中已经使用过大量的示例,这里我们使用 await ,去完成一些完全相同的功能。

    Task:


           public static void T1()
           {
               Task task = new Task(() => { });
               task.Wait();
           }

           public static async void T2()
           {
               Task task = new Task(() => {  });
               await task;
           }

    说明,await 可以让程序等待任务完成。

    Task<TResult>:


          public void T3()
          {
              // 获取 Task 任务对象,后面的逻辑过程可以弄成异步
              Task<int> task = TestAsync();

    // 任务是异步在执行,我不理会他
              // 这里可以处理其它事情,处理完毕后,再获取执行结果
              // 这就是异步

    Console.WriteLine(task.Result);
          }


           public async void T4()
           {
               // 使用 await 关键字,代表等待执行完成,同步
               int time = await TestAsync();
               Console.WriteLine(time);
           }

    说明:await 可以让程序等待任务执行完成,并且获得执行结果。

    看到没有。。。await 关键字,作用是让你等,是同步的,压根不是直接让你的任务变成异步后台执行的。

    那为啥提到 async 、await,都是说跟异步有关?不急,后面解释。

    说说 async Task<TResult>

    async Task<TResult> 修饰一个方法,那么这个方法要返回 await Task<TResult> 的结果。

    一篇文章弄懂C#中的async和await

    两种同步方式示例对比:


           public static int Test()
           {
               Task<int> task = new Task<int>(() =>
               {
                   // 模拟洗衣服的时间
                   int time = new Random().Next(2, 6);
                   Thread.Sleep(TimeSpan.FromSeconds(time));
                   return time;
               });
               task.Start();
               return task.Result;
           }

           public static async Task<int> TestAsync()
           {
               Task<int> task = new Task<int>(() =>
               {
                   // 模拟洗衣服的时间
                   int time = new Random().Next(2, 6);
                   Thread.Sleep(TimeSpan.FromSeconds(time));
                   return time;
               });
               task.Start();
               int time = await task;
               return time;
           }

    同步异步?

    问:async 和 await 不是跟异步方法有关嘛,为啥前面的示例使用了 await ,全部变成同步了?

    问:使用 async 和 await 的方法,执行过程到底是同步还是异步?

    答:同步异步都行,要同步还是异步,全掌握在你的手上。

    • 你使用 await 去调用一个异步方法,其执行过程就是同步。

    • 你获取异步方法返回的 Task,就是异步。

    最近笔者收到一些提问,有些读者,使用 async 和 await 去编写业务,想着是异步,可以提升性能,实际结果还是同步,性能一点没有提升。通过下面的示例,你会马上理解应该怎么用。

    首先,在不使用 async 和 await 关键字的情况下,我们来编写两个方法,分别实现同步和异步的功能,两个方法执行的结果是一致的。


           /// <summary>
           /// 同步
           /// </summary>
           /// <returns></returns>
           public static int Test()
           {
               Task<int> task = new Task<int>(() =>
               {
                   return 666;
               });
               task.Start();
               return task.Result;
           }

    /// <summary>
           /// 异步
           /// </summary>
           /// <returns></returns>
           public static Task<int> TestAsync()
           {
               Task<int> task = new Task<int>(() =>
               {
                   return 666;
               });
               task.Start();
               return task;
           }

    能不能将两个方法合并在一起呢?想同步就同步,想异步就异步,这样就不需要写两个方法了!

    是可以的!通过 async 和 await 关键字,可以轻松实现!

    合并后,代码如下:


           /// <summary>
           /// 可异步可同步
           /// </summary>
           /// <returns></returns>
           public static async Task<int> TestAsync()
           {
               Task<int> task = new Task<int>(() =>
               {
                   return 666;
               });
               task.Start();
               return await task;
           }

    合并后,我们又应该怎么在调用的时候,实现同步和异步呢?

    笔者这里给出两个示例:


           // await 使得任务同步
           public async void T1()
           {
               // 使用 await 关键字,代表等待执行完成,同步
               int time = await TestAsync();
               Console.WriteLine(time);
           }

    // 直接获得返回的 Task,实现异步
           public void T2()
           {
               // 获取 Task 任务对象,后面的逻辑过程可以弄成异步
               Task<int> task = TestAsync();

    // 任务是异步在执行,我不理会他
               // 这里可以处理其它事情,处理完毕后,再获取执行结果
               // 这就是异步

    Console.WriteLine(task.Result);
           }

    至此,理解为什么使用了 async 和 await,执行时还是同步了吧?

    Task封装异步任务

    前面,我们都是使用了 new Task() 来创建任务,而且微软官网大多使用 Task.Run() 来编写 async 和 await 的示例。

    因此,我们可以修改前面的异步任务,改成:


           /// <summary>
           /// 可异步可同步
           /// </summary>
           /// <returns></returns>
           public static async Task<int> TestAsync()
           {
               return await Task.Run<int>(() =>
               {
                   return 666;
               });
           }

    关于跳到 await 变异步

    在百度学习异步的时候,往往会有作者说,进入异步方法后,同步执行代码,碰到 await 后就是异步执行。

    当然还有多种说法。

    我们已经学习了这么多的任务(Task)知识,这一点十分容易解释。

    因为使用了 async 和 await 关键字,代码最深处,必定会出现 Task 这个东西,Task 这个东西本来就是异步。碰到 await 出现异步,不是因为 await 的作用,而是因为最底层有个 Task。

    一篇文章弄懂C#中的async和await

    为什么出现一层层的 await

    这是相对于提供服务者来说。因为我要提供接口给你使用,因此底层出现 async、await 后,我会继续保留方法是异步的(async),然后继续封装,这样就有多层的调用结构,例如上一小节的图。

    但是如果来到了调用者这里,就不应该还是使用 async 、await 去编写方法,而是应该按照实际情况同步或异步。

    来源:https://mp.weixin.qq.com/s/53EgxZHzEZJvbRmhaXA8eg

    标签:c#,async,await
    0
    投稿

    猜你喜欢

  • Android中ToggleButton开关状态按钮控件使用方法详解

    2022-11-10 06:24:35
  • 通过JDK源码学习InputStream详解

    2022-09-10 19:50:29
  • Android实现点击获取验证码60秒后重新获取功能

    2021-09-21 22:42:01
  • java中form以post、get方式提交数据中文乱码问题总结

    2022-12-15 06:53:59
  • 解析C#彩色图像灰度化算法的实现代码详解

    2022-01-26 07:34:55
  • 基于hibernate框架在eclipse下的配置方法(必看篇)

    2022-11-09 20:30:26
  • android轻量级无侵入式管理数据库自动升级组件

    2023-12-09 15:36:01
  • Android 媒体开发之MediaPlayer状态机接口方法实例解析

    2023-04-20 06:53:22
  • C#制作鹰眼的详细全过程(带注释)实例代码

    2022-03-01 06:56:12
  • Android中使用七牛云存储进行图片上传下载的实例代码

    2023-12-17 11:56:35
  • java 方法重写与权限修饰符以及多态和抽象类详解概念和用法

    2023-12-01 15:54:53
  • Java实现删除排序数组中重复元素的方法小结【三种方法比较】

    2023-09-28 15:21:48
  • SpringBoot如何优雅的整合Swagger Api自动生成文档

    2022-08-10 00:49:29
  • Java函数式编程(八):字符串及方法引用

    2022-05-02 22:28:23
  • 使用SpringBoot跨系统调用接口的方案

    2022-10-14 21:35:18
  • Spring中基于xml的AOP的详细步骤

    2022-10-17 13:38:32
  • 关于C#操作文件路径(Directory)的常用静态方法详解

    2023-06-06 10:40:12
  • Unity使用多态制作计算器功能

    2022-10-15 02:50:06
  • android Handler详细使用方法实例

    2022-11-29 01:35:12
  • Android应用开发中Fragment间通信的实现教程

    2023-02-23 18:06:46
  • asp之家 软件编程 m.aspxhome.com