微软的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