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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • asp.net获取系统当前时间的方法详解

    asp.net获取系统当前时间的方法详解

    这篇文章主要介绍了asp.net获取系统当前时间的方法,较为详细的分析了C#日期与时间操作所涉及的相关函数与使用技巧,需要的朋友可以参考下
    2016-06-06
  • c# 播放声音的四种方法

    c# 播放声音的四种方法

    这篇文章主要介绍了c# 播放声音的四种方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2020-11-11
  • c# 操作word写入特殊字符的实例

    c# 操作word写入特殊字符的实例

    这篇文章主要介绍了c# 操作word写入特殊字符的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • C#怎么给PDF添加背景图片

    C#怎么给PDF添加背景图片

    无论是办公还是日常生活中都经常会用到,很多时候,PDF文件的背景色都是白色,看多了难免觉得累,更换PDF的背景不仅可以让眼睛看起来更舒服,还可以让PDF文件看上去更美观。这篇文章我主要写的是如何使用C# 给PDF文件添加图片背景
    2016-02-02
  • C#实现动态数据绘图graphic的方法示例

    C#实现动态数据绘图graphic的方法示例

    这篇文章主要介绍了C#实现动态数据绘图graphic的方法,结合实例形式分析了C#根据动态数据绘制2D数据表格的相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • C#多线程学习之(四)使用线程池进行多线程的自动管理

    C#多线程学习之(四)使用线程池进行多线程的自动管理

    这篇文章主要介绍了C#多线程学习之使用线程池进行多线程的自动管理,实例分析了C#中线程池的概念与相关的使用技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • c#冒泡排序算法示例

    c#冒泡排序算法示例

    这篇文章主要介绍了c#冒泡排序算法示例,需要的朋友可以参考下
    2014-04-04
  • UGUI ScrollRect实现带按钮翻页支持拖拽

    UGUI ScrollRect实现带按钮翻页支持拖拽

    这篇文章主要为大家详细介绍了UGUI ScrollRect实现带按钮翻页支持拖拽,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • WPF实现2048小游戏

    WPF实现2048小游戏

    这篇文章主要为大家详细介绍了WPF实现2048小游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • C#中多线程Tread的使用(推荐)

    C#中多线程Tread的使用(推荐)

    线程是操作系统分配CPU时间的基本单元,在一个进程中可以有多个线程同时执行代码,这篇文章主要介绍了C#中多线程的使用Tread,需要的朋友可以参考下
    2022-10-10

最新评论