【C#复习总结】 Async 和 Await 的异步编程
谈到异步,必然要说下阻塞,在知乎上看到了网友举的例子非常省动,在这里我引用下。
怎样理解阻塞非阻塞与同步异步的区别?
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。1 老张把水壶放到火上,立等水开。(同步阻塞)老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)老张觉得这样傻等意义不大4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
有了对异步的理解,接下来我们就进入主题,讲一下Async 和 Await 。
关于这个话题阻塞非阻塞与同步异步,请看这篇文章讲的挺详细的:20分钟读懂进程线程、同步异步、阻塞非阻塞、并发并行
1 含义
C# 5 引入使用 Async 和 Await 的异步编程,C# 中的 Async 和 Await 关键字是异步编程的核心。 通过这两个关键字,可以使用 .NET Framework、.NET Core 或 Windows 运行时中的资源,轻松创建异步方法(几乎与创建同步方法一样轻松)。 使用 async 关键字定义的方法简称为“异步方法”。
2 作用
异步对可能会被屏蔽的活动(如 Web 访问)至关重要。 对 Web 资源的访问有时很慢或会延迟。 如果此类活动在同步过程中被屏蔽,整个应用必须等待。 在异步过程中,应用程序可继续执行不依赖 Web 资源的其他工作,直至潜在阻止任务完成。
下表显示了异步编程提高响应能力的典型区域。 列出的 .NET 和 Windows 运行时 API 包含支持异步编程的方法。
|
应用程序区域 |
包含异步方法的 .NET 类型 |
包含异步方法的 Windows 运行时类型 |
|
Web 访问 |
HttpClient |
SyndicationClient |
|
使用文件 |
StreamWriter, StreamReader, XmlReader |
StorageFile |
|
使用图像 |
MediaCapture, BitmapEncoder, BitmapDecoder |
|
|
WCF 编程 |
同步和异步操作 |
由于所有与用户界面相关的活动通常共享一个线程,因此,异步对访问 UI 线程的应用程序来说尤为重要。 如果任何进程在同步应用程序中受阻,则所有进程都将受阻。 你的应用程序停止响应,因此,你可能在其等待过程中认为它已经失败。
使用异步方法时,应用程序将继续响应 UI。 例如,你可以调整窗口的大小或最小化窗口;如果你不希望等待应用程序结束,则可以将其关闭。
3 用法及示例
C# 中的 Async 和 Await 关键字是异步编程的核心。 通过这两个关键字,可以使用 .NET Framework、.NET Core 或 Windows 运行时中的资源,轻松创建异步方法(几乎与创建同步方法一样轻松)。 使用 async 关键字定义的异步方法简称为“异步方法”。
代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; // 添加Using指令
using System.Net.Http; namespace async_await
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void StartButton_Click_Click(object sender, EventArgs e)
{ int contentLength = await AccessTheWebAsync(); resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
/// <summary>
/// 签名要注意3点
/// 1.必须要有异步修饰符async
/// 2.返回类型必须是 Task 或者 是 Task<T>
/// 3.方法结尾必须是 Async
/// </summary>
/// <returns></returns>
async Task<int> AccessTheWebAsync()
{
//添加Http客户端声明引用
HttpClient client = new HttpClient(); //GetStringAsync返回一个字符串,如果不异步的话,此步可能浪费很长时间 Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); //做其他的事
DoIndependentWork(); /*等待操作员暂停访问AccessTheWebAsync ;直到GetStringAsync,才可以继续;与此同时,控制权返回给AccessTheWebAsync;
* 当GetStringAsync 完成时,控制从此处继续 */
string urlContents = await getStringTask; //返回长度
return urlContents.Length;
} void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
}
}
4 异步方法的运行机制
异步编程中最需弄清的是控制流是如何从方法移动到方法的。 下图可引导你完成该过程。

5 关系图中的数值对应于以下步骤。
1 事件处理程序调用并等待 AccessTheWebAsync 异步方法。
2 AccessTheWebAsync 可创建 HttpClient 实例并调用 GetStringAsync 异步方法以下载网站内容作为字符串。
3 GetStringAsync 中发生了某种情况,该情况挂起了它的进程。 可能必须等待网站下载或一些其他阻止活动。 为避免阻止资源,GetStringAsync 会将控制权出让给其调用方 AccessTheWebAsync。
GetStringAsync 返回 Task,其中 TResult 为字符串,并且 AccessTheWebAsync 将任务分配给 getStringTask 变量。 该任务表示调用 GetStringAsync 的正在进行的进程,其中承诺当工作完成时产生实际字符串值。
4 由于尚未等待 getStringTask,因此,AccessTheWebAsync 可以继续执行不依赖于 GetStringAsync 得出的最终结果的其他工作。 该任务由对同步方法 DoIndependentWork 的调用表示。
5 DoIndependentWork 是完成其工作并返回其调用方的同步方法。
6 AccessTheWebAsync 已用完工作,可以不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。
因此,AccessTheWebAsync 使用一个 await 运算符来挂起其进度,并把控制权交给调用 AccessTheWebAsync 的方法。 AccessTheWebAsync 将 Task(Of Integer) 或 Task<int> 返回至调用方。 该任务表示对产生下载字符串长度的整数结果的一个承诺
说明:
如果 GetStringAsync在 AccessTheWebAsync 等待前完成,则控件会保留在 AccessTheWebAsync 中。 如果异步调用过程 (getStringTask) 已完成,并且 AccessTheWebSync 不必等待最终结果,则挂起然后返回到 AccessTheWebAsync 将造成成本浪费。
在调用方内部(此示例中的事件处理程序),处理模式将继续。 在等待结果前,调用方可以开展不依赖于 AccessTheWebAsync 结果的其他工作,否则就需等待片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。
7 GetStringAsync 完成并生成一个字符串结果。 字符串结果不是通过按你预期的方式调用 GetStringAsync 所返回的。(请记住,此方法已在步骤 3 中返回一个任务。)相反,字符串结果存储在表示完成方法 getStringTask 的任务中。 await 运算符从 getStringTask 中检索结果。 赋值语句将检索到的结果赋给 urlContents。
8 当 AccessTheWebAsync 具有字符串结果时,该方法可以计算字符串长度。 然后,AccessTheWebAsync 工作也将完成,并且等待事件处理程序可继续使用。
推荐阅读:【Async/Await异步编程中的最佳做法】【走进异步编程的世界 - 开始接触 async/await】【Async and Await】
【C#复习总结】 Async 和 Await 的异步编程的更多相关文章
- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...
- 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...
- 使用Async和Await进行异步编程(C#版 适用于VS2015)
你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...
- 使用Async和Await进行异步编程(C#版 适用于VS2015) z
你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...
- Async和Await进行异步编程
使用Async和Await进行异步编程(C#版 适用于VS2015) 你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很 ...
- 转:[你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
- [你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
- Async 和 Await 的异步编程 资料汇总
使用 Async 和 Await 的异步编程 https://msdn.microsoft.com/zh-cn/library/hh191443(v=vs.120).aspx 异步程序中的控制流 ht ...
- 四、C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 .NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就 ...
随机推荐
- Django 类视图
引文 所有的类视图都继承django.views.generic.base.View类. 在URLconf中简单的使用通用视图 如果只是简单的做一些属性修改,可以使用as_view()方法,如下所示: ...
- ORACLE获取SQL绑定变量值的方法总结
本文总结一下ORACLE数据库中如何获取SQL绑定变量值的方法,在SQL优化调优过程中,经常会用到这方面的知识点.在此梳理.总结一下,方面日后查找.翻阅. 方法1:查询V$SQL V$SQL视图中 ...
- Python操作字典(dict)
一.字典定义 >>> dict={} 二.字典元素添加 >>> dict['性别']='男' >>> dict {'性别': '男'} >& ...
- c/c++ 友元的简单应用
友元的简单应用 1,对象 + 对象,或者,对象 + 数字,可以用类的成员函数去重载+号函数,但是,数字 + 对象就不能用类的成员函数去重载+号函数了, 因为编译器会把数字 + 对象翻译成数字.oper ...
- 【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)
一.前言及参考资料 C Preprocessor即所谓的C预处理器,C++也继承了C的预处理程序,但在C++语言的设计与演化一书中,C++的设计者Bjarne Strustrup提及他从未喜欢过C预处 ...
- mongodb初级
上班第一天,先玩玩mongdb! 1:下载安装就不说了 2:启动服务 mongod 通常会报错: 原因:mongodb会使用默认的数据库存储路径是data/db,刚安装好的mongodb是不存在该路 ...
- ServletContextListener的作用
ServletContextListener是对ServeltContext的一个监听.servelt容器启动,serveltContextListener就会调用contextInitialized ...
- JSP内置九个对象Request请求对象
jsp内置对象是什么呢? 例如Java语言使用一个对象之前需要实例化(也就是所说的new一个对象),创建对象这个过程有点麻烦,所以在jsp中提供了一些内置对象,用来实现很多jsp应用.在使用内置对象时 ...
- C# SHA256加密算法记录
using System.Text; using System.Diagnostics; using System.Security; using System.Security.Cryptograp ...
- postgresql + mybatis insert主键自增方法
postgresql + mybatis插入记录时设置自增主键方法: 一.数据库设置主键自增 1.数据库中id字段选择serial4类型后,会在默认值中生成 nextval('app_id_seq': ...