关于async和await的一些误区

微软的MSDN说async和await是“异步”,可是很多人(包括笔者本身)有一些误区须要澄清:为何await语句以后没有执行?不是异步吗?多线程

  【示例代码】异步

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

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

var results = from ……
              select ……;

foreach(var r in results)
{
  ……
}

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

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

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

咱们进一步能够这样对比:code

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

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

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

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

在LINQ中,你若是须要当即执行,可使用扩展方法:

var results = (from ……
              select ……).ToList();

由于当即使用到了这个LINQ语句,因此会被当即执行。

一样地,异步等待也能够变成相似Wait同样的同步等待:

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

由于Processing原本就返回Task,固然也可使用Wait进行同步等待。

参考文献:http://blog.csdn.net/ma_jiang/article/details/37884915

相关文章
相关标签/搜索