.Net异步编程模式
异步编程模式的英文全称是The Asynchronous Programming Models,简称是APM。简单说明一下为什么要异步编程,以及异步编程带来的好处有:
1. 快速响应的用户界面
对于用户界面而言,它的响应用户的能力是非常关键的。如果耗时的操作阻塞了UI线程,造成UI线程不能响应用户操作。用户就会抛弃我们的系统。所以我们需要一种机制,在发起耗时操作的请求之后要立即返回,不要阻塞UI线程,让UI线程可以继续响应用用户的操作。然后等耗时操作返回后,通过回调来处理耗时操作返回的结果。
2. 更高的伸缩性
在服务端应用中,有非常多的IO操作:数据库访问,磁盘操作,Socket访问等。对于这些IO操作,单独占用一个线程来同步处理,浪费服务器的资源,使用IOCP异步方式可以有效解决这种问题,关于IOCP的具体信息,可以阅读本订阅号之前的文章。
所以我们需要掌握异步编程的技能。在.Net Framework中,可以实现异步编程的方式有很多种,今天我们主要分析四种异步的方式:
1. The Standard APM
2. The Event-based APM
3. The Task-based APM
4. The Await Async APM
一、The Standard APM
在FCL提供了具有BeginXxx和EndXxx方法的各种类型,一般这种命名的方法,就提供了Standard APM的支持。通常BeginXxx方法具有Xxx方法相同的参数以外,还有两个附加参数:callback和stateObject。callback就是异步的回调方法,它需要接受一个IAsyncResult类型的参数,然后在回调方法中访问它的AsyncState属性就可以得到stateObject的值。示例代码:
class StandardAPM
{
public static void Test()
{
Console.WriteLine("1. Begin");
WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
request.BeginGetResponse(DoCallback, request);
Console.WriteLine("2. Sync continue");
}
static void DoCallback(IAsyncResult ar)
{
WebRequest request = (WebRequest)ar.AsyncState;
WebResponse response = request.EndGetResponse(ar);
request.Abort();
response.Close();
Console.WriteLine("3. Async callback");
}
}
通过使用Standard APM,您的代码变得更加复杂,代码逻辑不清楚。
二、The Event-based APM
框架类库(FCL)还附带了一些支持基于事件的APM的类型。例如,在使用System.Net.WebClient类的时候,通过调用DownloadDataAsync方法,并且把回调方法订阅在DownloadDataCompleted事件上,可以帮助我们达到异步效果。程序开始异步操作从指定的URL下载数据,当它完成时,将触发DownloadDataCompleted事件。示例代码:
class EventBasedAPM
{
public static void Test()
{
WebClient wc = new WebClient();
wc.DownloadDataCompleted += DoCompleted;
Console.WriteLine("1. Begin");
wc.DownloadDataAsync(new Uri("https://www.baidu.com"));
Console.WriteLine("2. Sync continue");
}
public static void DoCompleted(object sender
, DownloadDataCompletedEventArgs e)
{
Console.WriteLine("3. Async callback");
}
}
实际上它的作用与使用BeginXxx和EndXxx方法相同,区别在于基于事件的APM更接近对象模型层,但是FCL支持基于事件APM的类型非常少,个人建议尽可能不要使用这种模式。
三、The Task-based APM
.NETFramework4.0引入了用于并行计算和异步编程的新任务并行库(TPL)。在System.Threading.Tasks命名空间中定义的主要使用的Task类表示要完成的用户工作项,要使用基于任务的APM,您必须创建Task的新实例,或者Task<T>类,传递Action或Action<T>委托的实例作为Task或Task<T>构造函数的第一个参数,然后调用Task的实例方法Start,通知任务调度程序尽快安排此任务。示例代码:
class TaskBasedAPM
{
public static void Test()
{
Console.WriteLine("1. Begin");
DoAsync();
Console.WriteLine("2. Sync continue");
}
static void DoAsync()
{
WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
Task<WebResponse> task = request.GetResponseAsync();
task.ContinueWith(t => {
request.Abort();
t.Result.Close();
Console.WriteLine("3. Async callback");
});
}
}
四、The Await Async APM
在C# 5.0中引入了async和await关键字,它们是异步编码的语法糖,在C#编译器进行编译之后,能够达到异步的效果,写出来的代码更加接近同步代码,逻辑更加清楚,易于阅读。它的异步原理是和Task-based APM一样的。示例代码:
class AwaitAsyncAPM
{
public static void Test()
{
Console.WriteLine("1. Begin");
DoAsync();
Console.WriteLine("2. Sync continue");
}
static async Task DoAsync()
{
WebRequest request = HttpWebRequest.Create("http://www.baidu.com");
WebResponse webResponse = await request.GetResponseAsync();
request.Abort();
webResponse.Close();
Console.WriteLine("3. Async callback");
//使用await和async关键字定义的异步方法,可以return返回值也可以没有。
//有没有return语句的时候,异步方法返回的是Task
//有return语句的时候,异步方法返回的是Task<ResultType>
//当调用返回的task.Result的时候,线程会阻塞,并等待异步方法真实返回结果。
}
}
最后在这四种方式进行总结:
The Standard APM: 是基于线程池实现的,可以广泛使用,标准,推荐,支持取消和延续。
The Event-based APM: 是基于线程池实现的,尽量避免使用,不建议使用。
The Task-based APM: 是指定的任务调度程序,推荐,支持线程池模式的所有功能,并具有许多其他功能。
The Await Async APM: 是基于Task-based APM的模式,新的C#5.0异步模式,推荐使用。
- JavaScript Alert 函数执行顺序问题
- 算法模板——计算几何1(图形面积)
- 算法模板——线段树6(二维线段树:区域加法+区域求和)(求助phile)
- 【LeetCode 242】 关关的刷题日记36 Valid Anagram
- javascript闭包
- 【LeetCode 438】关关的刷题日记37 Find All Anagrams in a String
- 还在手动给css加前缀?no!几种自动处理css前缀的方法简介
- 算法模板——线段树5(区间开根+区间求和)
- Spring基础篇——通过Java注解和XML配置装配bean
- Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition
- 算法模板——线段树1(区间加法+区间求和)
- 【LeetCode 205】关关的刷题日记38 Isomorphic Strings
- JavaScript基础2---控制权DOM操作
- 算法模板——线段树3(区间覆盖值+区间求和)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- windows安装nginx注册为服务的正确姿势 并设置开机自启 实践笔记
- windows navicat连接oracle11G 自用 实践笔记
- docker安装官方redis集群并集群连接测试 的正确姿势 自用 实践笔记
- Asp.net Core 使用Jenkins + Dockor 实现持续集成、自动化部署(一):Jenkins安装
- Centos7安装轻量级TCP转发工具rinetd注册为服务的正确姿势 并设置开机自启 实践笔记 自用
- Connection open error . Connection Timeout Expired. The timeout period elapsed during the post-login
- macbook-12-2015款 安装win10系统 自用 实践笔记
- OpenGL ES 之attribute
- windows server 2012 r2 搭建文件服务器 问题记录 自用 实践笔记
- OpenGL ES 之uniform和varying
- OpenGL ES 绘制纹理
- Win10+Unlocker3+VMware15.5+MacOS10.14+xcode+QT for ios+虚拟机苹果系统 自用 实践笔记
- OpenGL ES 纹理过滤模式-glTexParameteri
- Jenkins时间修改为北京时间
- OpenGL ES for Android 绘制一个点