C# 1.0 新特性之异步委托(AP、APM)
Ø 前言
C# 异步委托也是属于异步编程中的一种,可以称为 Asynchronous Programming(异步编程)或者 Asynchronous Programming Model(异步编程模型),因为这是实现异步编程的模式。委托是 C#1.0 就有的特性,并且 .NET v1.0 同时也伴随有 AsyncCallback、IAsyncResult 等类/接口的出现,所以所有的 .NET 版本中都是支持的。
1. 什么是异步委托
1) 异步委托是采用异步回调的方式实现异步执行,当使用委托异步执行某个方法时,将从线程池中取出一个线程去执行该方法。
2) 当执行完成后则调用 AsyncCallback 委托指定的方法,完成异步回调。
3) 开始执行一个异步委托后,可以使用4种方式等待异步执行完成:
1. 开启异步委托后,BeginInvoke() 方法将返回一个实现了 IAsyncResult 接口的 System.Runtime.Remoting.Messaging.AsyncResult 对象。使用该对象的 AsyncWaitHandle 属性,并调用 WaitOne() 方法,该方法会阻塞当前线程,直到收到信号(异步委托方法执行完成)。
2. 调用委托对象的 EndInvoke() 方法,需要传递一个 AsyncResult 对象,该方法也用于获取异步委托的返回值,所以这种方式也会阻塞当前线程。
3. 使用 IAsyncResult.IsCompleted 属性,判断是否执行完成。该属性在异步委托方法执行完成时为 true.
4. 【推荐】使用异步回调委托的方式,当异步委托方法执行完成后调用,如果在不需要非要等到异步完成时获取返回结果的情况下,推荐使用该方式。
2. 下面分别使用这四种方式等待
首先,定义四个委托类型。
public delegate void MyDelegate1();
public delegate string MyDelegate2();
public delegate void MyDelegate3(string str);
public delegate int MyDelegate4(int num1, int num2);
1) 使用 WaitOne() 方法(匿名方法)
/// <summary>
/// 使用 WaitOne() 方法(匿名方法)。
/// </summary>
public void AsyncDelegateTest1()
{
WriteLine("AsyncDelegateTest1() 方法开始执行,线程Id:{0}", GetThreadId());
MyDelegate1 d1 = new MyDelegate1(delegate()
{
WriteLine("匿名方法开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
Thread.Sleep(3000);
WriteLine("匿名方法结束执行,线程Id:{0}", GetThreadId());
});
IAsyncResult ar = d1.BeginInvoke(null, null);
ar.AsyncWaitHandle.WaitOne(); //这里将阻塞线程,直到收到信号(异步方法执行完成)
WriteLine("AsyncDelegateTest1() 方法结束执行,线程Id:{0},{1}", GetThreadId(), GetTime());
}
运行以上代码:

2) 使用委托对象的 EndInvoke() 方法(匿名方法)
/// <summary>
/// 使用委托对象的 EndInvoke() 方法(匿名方法)。
/// </summary>
public void AsyncDelegateTest2()
{
WriteLine("AsyncDelegateTest2() 方法开始执行,线程Id:{0}", GetThreadId());
MyDelegate2 d2 = new MyDelegate2(delegate()
{
WriteLine("匿名方法开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
Thread.Sleep(3000);
WriteLine("匿名方法结束执行,线程Id:{0}", GetThreadId());
return System.Reflection.MethodBase.GetCurrentMethod().Name;
});
IAsyncResult ar = d2.BeginInvoke(null, null);
string result = d2.EndInvoke(ar); //这里也将阻塞线程,直到异步方法执行完成
WriteLine("AsyncDelegateTest2() 方法结束执行,{0},异步委托返回结果:{1}", GetTime(), result);
}
运行以上代码:

3) 使用 IAsyncResult.IsCompleted 属性(Lambda 表达式)
/// <summary>
/// 使用 IAsyncResult.IsCompleted 属性(Lambda 表达式)。
/// </summary>
public void AsyncDelegateTest3()
{
WriteLine("AsyncDelegateTest3() 方法开始执行,线程Id:{0}", GetThreadId());
MyDelegate3 d3 = new MyDelegate3((str) =>
{
WriteLine("Lambda 表达式开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
Thread.Sleep(3000);
WriteLine("Lambda 表达式结束执行,str:{0}", str);
});
IAsyncResult ar = d3.BeginInvoke("这是一段话!", null, null);
while (!ar.IsCompleted) //标记是否完成(其实与直接调 EndInvoke() 方法没什么区别)
{ }
WriteLine("AsyncDelegateTest3() 方法结束执行,线程Id:{0},{1}", GetThreadId(), GetTime());
}
运行以上代码:

4) 【推荐】使用异步回调委托
/// <summary>
/// 【推荐】使用异步回调委托。
/// </summary>
public void AsyncDelegateTest4()
{
WriteLine("AsyncDelegateTest4() 方法开始执行,线程Id:{0}", GetThreadId());
MyDelegate4 d4 = new MyDelegate4(Add);
//这里必须将第二个参数(委托对象)传入,否则异步回调中 IAsyncResult.AsyncState 属性将为 null.
IAsyncResult ar = d4.BeginInvoke(22, 36, new AsyncCallback(AddCallback), d4);
WriteLine("AsyncDelegateTest4() 方法结束执行,线程Id:{0}", GetThreadId());
}
public int Add(int num1, int num2)
{
WriteLine("Add() 方法开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
Thread.Sleep(3000);
WriteLine("Add() 方法结束执行,线程Id:{0}", GetThreadId());
return num1 + num2;
}
public void AddCallback(IAsyncResult ar)
{
WriteLine("AddCallback() 方法开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
MyDelegate4 d4 = ar.AsyncState as MyDelegate4; //获取委托对象
int result = d4.EndInvoke(ar); //这里并不会阻塞
WriteLine("AddCallback() 方法结束执行,计算结果:{0},{1}", result, GetTime());
}
运行以上代码:

3. 下面,再来看下 C# 中一些常用基于异步回调的运用
1) 模拟 Web 请求,异步读取响应流
/// <summary>
/// 异步获取网页 HTML 内容。
/// </summary>
public void AsyncGetHtmlString()
{
WriteLine("AsyncGetHtmlString() 方法开始执行,线程Id:{0},{1}", GetThreadId(), GetTime());
WebRequest request = WebRequest.Create("http://www.cnblogs.com/abeam/");
request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
WriteLine("AsyncGetHtmlString() 方法结束执行,线程Id:{0}", GetThreadId());
}
public async void ResponseCallback(IAsyncResult ar)
{
WriteLine("ResponseCallback() 方法开始执行(此时已经获得响应),线程Id:{0},{1}", GetThreadId(), GetTime());
WebRequest request = ar.AsyncState as WebRequest;
using (WebResponse response = request.EndGetResponse(ar))
{
using (var stream = response.GetResponseStream())
{
WriteLine("开始异步读取,线程Id:{0},{1}", GetThreadId(), GetTime());
WriteLine("响应的 HTML 内容:");
int count, totalCount = 0;
//1. 同步读取响应流
using (var sr = new System.IO.StreamReader(stream, Encoding.UTF8))
{
char[] chars = new char[256];
while ((count = sr.Read(chars, 0, chars.Length)) > 0)
{
totalCount += count;
if (totalCount <= chars.Length) //太多屏幕容不下
{
string content = new string(chars, 0, count);
WriteLine(content);
WriteLine("同步读取流线程Id:{0}", GetThreadId());
}
}
}
WriteLine("响应的 HTML 总字符数:{0}", totalCount);
//2. 异步读取响应流
/*
* byte[] buffer = new byte[stream.Length];
* int totalCount = await stream.ReadAsync(buffer, 0, buffer.Length);
* 不能使用 stream.Length,因为 stream 是一种 System.Net.ConnectStream,否者将报异常:
* 未处理System.NotSupportedException
* Message: “System.NotSupportedException”类型的未经处理的异常在 mscorlib.dll 中发生
* 其他信息: 此流不支持查找操作。
*/
byte[] buffer = new byte[1024];
while ((count = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
totalCount += count;
if (totalCount <= 1024) //太多屏幕容不下
{
string content = Encoding.UTF8.GetString(buffer);
Write(content);
}
WriteLine();
Write("异步读取流线程Id:{0}", GetThreadId());
}
WriteLine();
WriteLine("响应的 HTML 总字节数:{0}", totalCount);
}
}
}
下面是两种读取方式的结果:


Ø 总结
1. 异步委托主要使用 BeginInvoke() 方法开启异步委托,该方法传入一个回调委托 AsyncCallback 对象。
2. BeginInvoke() 返回一个实现了 IAsyncResult 接口的对象,可以使用该对象的 AsyncWaitHandle.WaitOne() 方法和 IsCompleted 属性判断异步是否完成。
3. 同样 AsyncCallback 委托的签名也有个 IAsyncResult 参数,该委托将在异步调用完成时执行。
4. 需要获取异步委托的返回结果,都必须调用 EndInvoke() 方法。
C# 1.0 新特性之异步委托(AP、APM)的更多相关文章
- 使用Servlet3.0新特性asyncSupported=true时抛异常java.lang.IllegalStateException: Not supported
最近在运用Servlet3.0新特性:异步处理功能的时候出现以下了2个问题: 运行时会抛出以下两种异常: 一月 19, 2014 3:07:07 下午 org.apache.catalina.core ...
- 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...
- 转:[你必须知道的异步编程]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#基础知 ...
- 四、C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 .NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就 ...
- C# 7.0 新特性2: 本地方法
本文参考Roslyn项目中的Issue:#259. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 ...
- c# 语法5.0 新特性 转自网络
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
- C#5.0新特性
C#5.0新特性 C#5.0最大的新特性,莫过于Async和Parallel. 以往我们为了让用户界面保持相应,我们可以直接使用异步委托或是System.Threading命名空间中的成员,但Syst ...
- Java基础加强-(注解,动态代理,类加载器,servlet3.0新特性)
1. Annotation注解 1.1. Annotation概述 Annotation是JDK 5.0以后提供对元数据的支持,可以在编译.加载和运行时被读取,并执行相应的处理.所谓Annota ...
随机推荐
- 【转】测试开发工程师必备软硬能力&高级测试开发工程师需要具备什么能力?
对于测试的基本知识,可以查看软件测试相关书籍 对于在公司成为一位优秀的测试开发工程师,我觉得下面这篇文章涉及到的是我们需要的,稍微进行改动https://blog.csdn.net/sinat_210 ...
- Qt 连接MySQL
工程文件 QT += sql 举例 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName(&q ...
- AI2(App Inventor 2)离线版服务器(AI伴侣2.47版)
提供这个版本的原因: 与app.gzjkw.net的源代码版本尽可能的接近,这样导入app.gzjkw.net源文件的时候不会有“该项目由新版App Inventor系统创建,我们仍然尝试将其加载,但 ...
- linux下oracle无法删除用户
Oracle删除用户的提示无法删除当前已连接用户.且无法kill掉用户进程的两种解决方法如下: 1.先锁定用户.然后查询进程号,最后删除对应的进程.在删除对应的用户 SQL>alter user ...
- Linux kernel workqueue机制分析【转】
转自:http://www.linuxsir.org/linuxjcjs/15346.html 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.1 ...
- 06webpack-- html-webpack-plugin的2个作用
<!-- 15 html-webpack-plugin的2个作用 下载 cnpm i html-webpack-plugin -D 作用在==>内存中生成页面 在webpack中 导入在内 ...
- Java同步和异步,阻塞和非阻塞
同步和异步.阻塞和非阻塞 同步和异步关注的是消息通信机制. 同步是指: 发送方发出数据后, 等待接收方发回响应后才发下一个数据包的通讯方式. 就是在发出一个调用时, 在没有得到结果之前, 该调用就不返 ...
- 【BZOJ3716】[PA2014]Muzeum(贪心+网络流)
BZOJ 题意: 在二维网格图中有\(n\)个物品,每个物品有价值:但有\(m\)个警卫看管这些物品,每个警卫面朝\(y\)轴负方向,能看到一定角度(假定能够看到无穷远). 现在每个敬畏有一个贿赂价钱 ...
- 【Spring IoC】BeanFactory 和 ApplicationContext(五)
一.BeanFactory容器 BeanFactory 容器是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.fac ...
- Linux查看网卡传输速率总结
1.使用ethtool命令 ethtool ens192 使用ethtool命令后面直接接网卡名称可以查看到部分信息,包括网卡协商速率等等. 还有一种如果服务器内有很多块网卡,我们想查看具体网 ...