zoukankan      html  css  js  c++  java
  • 关于async和await的一些误区实例详解

    转载自 http://www.jb51.net/article/53399.htm

    这篇文章主要介绍了关于async和await的一些误区实例详解,有助于更加深入的理解C#程序设计,需要的朋友可以参考下

    微软官方的MSDN上说async和await是“异步”,但是不少人(包括笔者自己)都有一些误区需要澄清:为什么await语句之后没有执行?不是异步吗?

    先举一个示例代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public partial class Form1 : Form
    {
     public async Task Processing()
     {
       await Task.Delay(5000);
       label1.Text = "Succuessful";
     }
     public Form1()
     {
       InitializeComponent();
        
     }
     private async void button1_Click(object sender, EventArgs e)
     {
       await Processing();
       MessageBox.Show("Button's event completed");
     }
    }

    很多人(包括笔者)一开始会觉得异步好像类似多线程一样,到await的时候会在后台先开启一个线程执行任务,随后主线程(这里是UI线程)将自动执行后面的部分(即弹出“Button's event completed”的消息框)。

    其实这个理解是错误的。async和await的本质其实是“yield return”和“LINQ”的“迭代式”等待。我们应该清楚一点:那就是你写了LINQ语句:

    1
    2
    3
    4
    5
    6
    7
    var results = from ……
           select ……;
     
    foreach(var r in results)
    {
     ……
    }

    当你下断点你会发觉results并不会立即执行,直到使用到results的地方(例子中也就是foreach这里)才会被执行(此时黄色跟踪调试的光棒又会折回到var results……这里,然后等到results执行完毕之后才真正进入foreach进行执行)。

    所以,async/await和LINQ的这种“迭代式”的“异步操作”是异曲同工的。只不过async/await本质是返回一个Task而已,而Task又是异步的(因为Task本质就是一个线程),所以真正执行到(使用到async方法的时候)带有await的方法的时候,后台才会真正开启一个线程去执行任务。此时主线程会等待这个Task线程直到其执行完毕(IsComplete属性为True为止)。所以界面是不会卡顿的。

    所以,await是Task的异步等待而已,并不是我们所谓的“异步操作”;拿它和LINQ作对比,你会发现LINQ执行顺序和它一致,只不过LINQ没有异步等待(当然没有!又没有开启线程啥的……)。

    我们进一步可以这样对比:

    LINQ:变量 = LINQ语句(表达式)

       等到使用LINQ变量的时候才折返到LINQ语句处真正执行LINQ语句。

    异步等待:变量 = 异步方法

        等到使用await+异步方法的时候才会折返到该异步方法处,开启线程真正执行异步方法,主线程被挂起(但不会造成界面死掉),直至子线程Task任务完全执行完毕为止。

    在LINQ中,你如果需要立即执行,可以使用扩展方法:

    var results = (from ……
                  select ……).ToList();
    因为立即使用到了这个LINQ语句,所以会被立即执行。

    同样地,异步等待也可以变成类似Wait一样的同步等待:

    1
    2
    3
    4
    5
    private async void button1_Click(object sender, EventArgs e)
    {
      Processing().GetAwaiter().GetResult();
      MessageBox.Show("Button's event completed");
    }

    因为Processing本来就返回Task,当然也可以使用Wait进行同步等待。

  • 相关阅读:
    用户场景故事
    我喜欢的输入法
    课堂练习-----查找水王
    《你的灯亮着吗》阅读笔记1
    补第二阶段冲刺站立会议6(原6月8日)
    补第二阶段冲刺站立会议5(原6月7日)
    补第二阶段冲刺站立会议4(原6月6日)
    补第二次冲刺站立会议3(原6月5日)
    补第二次冲刺站立会议2(原6月4日)
    补第二次阶段冲刺站立会议1(原6月3日)
  • 原文地址:https://www.cnblogs.com/herenwei-wayne/p/5385805.html
Copyright © 2011-2022 走看看