C#中async和await的深入分析

 更新时间:2022年11月09日 11:03:02   作者:code bean  
Async/Await是C# 5引入的关键字,用以提高用户界面响应能力和对Web资源的访问能力,同时它使异步代码的编写变得更加容易,下面这篇文章主要给大家介绍了关于C#中async和await的相关资料,需要的朋友可以参考下

大概理解

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

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

大多情况下,分开才能体现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执行效果,如下:

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

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

现在给出结论:

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,来看下程序的执行顺序:

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

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

这就更明了了, 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的文章就介绍到这了,更多相关C# async和await内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#温故而知新系列教程之闭包

    C#温故而知新系列教程之闭包

    闭包是将一些执行语句的封装,可以将封装的结果像对象一样传递,在传递时,这个封装依然能够访问到原上下文。下面这篇文章主要给大家介绍了关于C#中闭包的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-05-05
  • C#中的in参数与性能分析详解

    C#中的in参数与性能分析详解

    这篇文章主要给大家介绍了关于C#中in参数与性能分析的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • C#图表算法之最短路径

    C#图表算法之最短路径

    本文详细讲解了C#图表算法之最短路径,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Unity3D撤回命令开发详解

    Unity3D撤回命令开发详解

    这篇文章主要为大家详细介绍了Unity3D撤回命令开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • WPF实现3D翻牌式倒计时特效

    WPF实现3D翻牌式倒计时特效

    这篇文章主要为大家详细介绍了WPF实现3D翻牌式倒计时特效,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • C#实现的微信网页授权操作逻辑封装示例

    C#实现的微信网页授权操作逻辑封装示例

    这篇文章主要介绍了C#实现的微信网页授权操作逻辑封装,分析了微信网页授权操作的原理、步骤并给出了C#实现的网页授权操作逻辑封装类,需要的朋友可以参考下
    2016-10-10
  • 基于C#动手实现网络服务器Web Server

    基于C#动手实现网络服务器Web Server

    这篇文章主要为大家详细介绍了基于C#动手实现网络服务器Web Server,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • C#编程实现DataTable添加行的方法

    C#编程实现DataTable添加行的方法

    这篇文章主要介绍了C#编程实现DataTable添加行的方法,结合两个实例形式分析了C#操作DataTable实现动态添加行的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • 在C#语言里对NULL的技术处理小结

    在C#语言里对NULL的技术处理小结

    在 C# 中处理 null 值是编写可靠且可靠的代码的一个重要方面,在本文中,我将讨论一些在 C# 中处理 null 值的最常用技术,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • DevExpress实现根据行,列索引来获取RepositoryItem的方法

    DevExpress实现根据行,列索引来获取RepositoryItem的方法

    这篇文章主要介绍了DevExpress实现根据行,列索引来获取RepositoryItem的方法,需要的朋友可以参考下
    2014-08-08

最新评论