关于async和await的一些误区实例详解

 更新时间:2014年08月07日 15:37:14   投稿:shichen2014  
这篇文章主要介绍了关于async和await的一些误区实例详解,有助于更加深入的理解C#程序设计,需要的朋友可以参考下

微软官方的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和await的本质其实是“yield return”和“LINQ”的“迭代式”等待。我们应该清楚一点:那就是你写了LINQ语句:

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一样的同步等待:

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

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

相关文章

  • Unity的IPostprocessBuildWithReport实用案例深入解析

    Unity的IPostprocessBuildWithReport实用案例深入解析

    这篇文章主要为大家介绍了Unity的IPostprocessBuildWithReport实用案例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • C#/Java连接sqlite与使用技巧

    C#/Java连接sqlite与使用技巧

    无意中发现的,C#/Java连接sqlite与使用技巧。看了下,还挺不错的。与大家分享一下。
    2013-04-04
  • C#分布式事务的超时处理实例分析

    C#分布式事务的超时处理实例分析

    这篇文章主要介绍了C#分布式事务的超时处理,以实例形式较为详细的分析了C#分布式事务的超时处理相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • 关于C#中yield return用法的思考

    关于C#中yield return用法的思考

    在这篇文章中,我们将深入讨论 C# 中yield return的机制和用法,帮助您更好地理解这个强大的功能,并在实际开发中灵活使用它,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-05
  • c#自带缓存使用方法 c#移除清理缓存

    c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下
    2014-02-02
  • C#编程实现对象与JSON串互相转换实例分析

    C#编程实现对象与JSON串互相转换实例分析

    这篇文章主要介绍了C#编程实现对象与JSON串互相转换的方法,结合实例分析了在DoNet2.0与Donet3.5环境下实现对象与JSON转换的相关技巧,需要的朋友可以参考下
    2015-11-11
  • C#控件Picturebox实现鼠标拖拽功能

    C#控件Picturebox实现鼠标拖拽功能

    这篇文章主要为大家详细介绍了C#控件Picturebox实现鼠标拖拽功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • C#字符串如何提取数值(带小数点)

    C#字符串如何提取数值(带小数点)

    这篇文章主要介绍了C#字符串如何提取数值问题(带小数点),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • C#访问SQL Server数据库的实现方法

    C#访问SQL Server数据库的实现方法

    这篇文章主要介绍了C#访问SQL Server数据库的实现方法,以实例形式简单分析了C#连接、查询SQL Server数据库的具体技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • 算法练习之从String.indexOf的模拟实现开始

    算法练习之从String.indexOf的模拟实现开始

    这篇文章主要介绍了算法练习从String.indexOf的模拟实现开始,需要的朋友可以参考下
    2014-12-12

最新评论