关于async和await的⼀些误区实例详解
微软官⽅的MSDN上说async和await是“异步”,但是不少⼈(包括笔者⾃⼰)都有⼀些误区需要澄清:为什么await语句之后没有执⾏?不是异步吗?
先举⼀个⽰例代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18public partial class Form1 : Form
{
public async Task Processing()
{
await和async使用方法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 7var 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 3private async void button1_Click(object sender, EventArgs e) {
Processing().GetAwaiter().GetResult();
4 5 MessageBox.Show("Button's event completed"); }
因为Processing本来就返回Task,当然也可以使⽤Wait进⾏同步等待。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论