C#中async和await的深入分析

作者:code?bean 时间:2023-09-14 17:11:20 

大概理解

查了一个小时的资料:async和await

发现这个大神的解释一针见血,深得我心!以最简单的例子,解释了async和await。妙~~~

大多情况下,分开才能体现async和await的价值!

C#中async和await的深入分析

 但,await 并没有这么简单。

深入分析

await和Wait()的区别

接下来继续往下看:

await Task.Delay(3000);  和Task.Delay(3000).Wait();   有没有区别?

上代码:

using System.Diagnostics;

namespace await_async2
{
   internal class Program
   {

static  public void TestWait()
       {
           var t = Task.Factory.StartNew(() =>
           {
               Console.WriteLine("Start");
               Task.Delay(3000).Wait();
               Console.WriteLine("Done");
           });
           t.Wait();
           Console.WriteLine("All done");
       }

static public void TestWait2()
       {
           var t = Task.Factory.StartNew(async () =>
           {
               Console.WriteLine("Start");
               await Task.Delay(3000);
               Console.WriteLine("Done");
           });
           t.Wait();
           Console.WriteLine("All done");
       }

static public void TestWait3()
       {
           var t = Task.Run(async () =>
           {
               Console.WriteLine("Start");
               await Task.Delay(3000);
               Console.WriteLine("Done");
           });
           t.Wait();
           Console.WriteLine("All done");
       }

static void Main(string[] args)
       {
           TestWait2();
           //避免程序提前退出,导致一些现象看不到
           Task.Delay(5000).Wait();
       }
   }
}

首先,强调一下,最后一句 Task.Delay(5000).Wait(); 是必须的,不然,程序提前退出,导致一些现象看不到,从而蒙蔽了我们。

第1段代码TestWait执行效果,如下:

C#中async和await的深入分析

第2段代码TestWait2执行效果,如下:

C#中async和await的深入分析

第3段代码TestWait3执行效果,如下:

C#中async和await的深入分析

现在给出结论:

Task.Delay(3000).Wait(); 这个就是同步等。

await Task.Delay(3000); 因为没有分开来写(见第一张图),所以基本和同步等没有区别。

但是如果 await Task.Delay(3000); 是写到:Task.Factory.StartNew里面的

static public void TestWait2()
       {
           var t = Task.Factory.StartNew(async () =>
           {
               Console.WriteLine("Start");
               await Task.Delay(3000);
               Console.WriteLine("Done");
           });
           t.Wait();
           Console.WriteLine("All done");
       }

那这个效果不一样了,他们执行的权限丢出去了有点像python里的yeild,来看下程序的执行顺序:

C#中async和await的深入分析

 这里就看出了:await Task.Delay(3000);  和Task.Delay(3000).Wait(); 的区别了。(但是这种情况如果在道Task.Run里面就体现不出来!)

然后,我有简单做了一个实验:

C#中async和await的深入分析

这就更明了了, await Task.Delay(3000); 就像设置了一个回调,一旦三秒时间一到,程序的指针就会回到await Task.Delay(3000);后面的位置,直到函数执行结束。再回到之前的位置。这就是所谓的用同步的方式写异步的代码吧

但是,为啥在Task.Factory.StartNew才会体现出来,这个我就不清楚了,请各位大佬指点一下。

去掉Task.Run的Wait

再来对比一下,下面这两个函数:

static public void TestWait8()
{
    var t = Task.Run(async () =>
    {
        Console.WriteLine("Start");
        await Task.Delay(3000);
        Console.WriteLine("Done");
    });
    Console.WriteLine("All done");
}
static public void TestWait8_5()
{
    var t = Task.Factory.StartNew(async () =>
    {
        Console.WriteLine("Start");
        await Task.Delay(3000);
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

先看第一个TestWait8,由于Task.Run不再调用 t.Wait(),Task.Run内部这个线程主线程是并行的关系。程序指针会在两个线程中来回切换。如果一方中写了await xxx,那程序指针必然跳到另一个线程。直达await结束才可能返回。 这种情形是比较多的。此时await能节省大量等待时间(比如IO操作时间),充分利用等待时间。

此时 Console.WriteLine("All done");会最先被打印出来。

再看第二个TestWait8_5(其实就是回顾一下),当程序执行到t.Wait()时,程序不会继续向下了,(此时因为有t.Wait()的存在,所以子线程其实是优先于主线程的)而是进入到子线程的内部进程,试图将这个线程执行完,但是再线程里面遇到又遇到await Task.Delay(3000);此时程序指针不会再这里死等,程序指针又跳回主线程继续执行,直到三秒到了之后就会回到子线程,子线程执行完了之后,再回到主线程。

但是如果吧TestWait8_5 中    Task.Factory.StartNew 换成 Task.Run ,那么前面的过程一样,只是执行到await Task.Delay(3000);时候,此时会死等,不会跳到主线程,而是一定等到这个子线程完结,再回主线程。

小结

总结一下就是,遇到await 一定会等,至于程序指针是先跳到其他线程,还是在此线程死等,就看你的线程函数这么写的了。

其他

.Await();

最后,还有个:Task.Delay(3000).Await();

这个是prsim对Task写的的一个拓展方法(避免在主线程调用时,阻塞UI):

C#中async和await的深入分析

来源:https://blog.csdn.net/songhuangong123/article/details/127627231

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

猜你喜欢

  • Java单例模式实现静态内部类方法示例

    2021-08-03 00:36:51
  • Android实现长按back键退出应用程序的方法

    2023-03-26 21:49:43
  • 详解Android WebView监听console错误信息

    2021-08-29 18:20:40
  • Compose状态保存rememberSaveable原理解析

    2021-12-26 10:07:56
  • Netty启动流程注册多路复用源码解析

    2021-12-02 16:51:35
  • 浅谈Spring与SpringMVC父子容器的关系与初始化

    2023-02-08 12:09:05
  • C#中Socket通信用法实例详解

    2022-07-10 03:42:03
  • Windows下安装ElasticSearch的方法(图文)

    2023-11-25 13:35:35
  • C#使用NPOI导入Excel的方法详解

    2021-08-29 07:39:35
  • 仿orm自动生成分页SQL分享

    2022-11-09 22:48:30
  • C#使用Clipboard类实现剪贴板功能

    2022-09-29 06:03:54
  • Java基础之并发相关知识总结

    2022-04-24 13:59:05
  • java 实现简单圣诞树的示例代码(圣诞节快乐)

    2023-03-13 13:13:37
  • Android编程开发之性能优化技巧总结

    2022-08-26 13:23:00
  • SpringBoot2 实现JPA分页和排序分页的案例

    2022-02-23 13:26:08
  • Android利用传感器实现微信摇一摇功能

    2023-07-12 05:05:18
  • Java 由浅入深带你掌握图的遍历

    2022-05-21 07:21:44
  • Java使用组件编写窗口实现网上文件下载

    2023-09-14 06:08:36
  • 详解C#之委托

    2021-12-12 00:17:49
  • 腾讯开源消息中间件TubeMQ总体介绍分析

    2022-06-21 05:10:03
  • asp之家 软件编程 m.aspxhome.com