.NET中的异步编程-EAP/APM使用方法及案例介绍
程序员文章站
2024-03-05 19:50:37
从.net 4.5开始,支持的三种异步编程模式: •基于事件的异步编程设计模式 (eap,event-based asynchronous pattern) &...
从.net 4.5开始,支持的三种异步编程模式:
•基于事件的异步编程设计模式 (eap,event-based asynchronous pattern)
•异步编程模型(apm,asynchronous programming model)
•基于任务的编程模型(tap,task-based asynchronous pattern)
基于任务的异步模式 (tap) 是基于 system.threading.tasks 命名空间的 task 和 task<tresult>,用于表示任意异步操作。 tap 是新开发的建议异步设计模式,之后再讨论。
先总结一下旧有的2种模式:eap、apm。
从以下几个方面,看这2种异步编程方式的异同:
•命名、参数、返回值
•典型应用
•捕获异常
•状态
•取消操作
•进度报告
eap
命名、参数、返回值
eap的编程模式的代码命名有以下特点:
•将有一个或多个名为 “[方法名称]async” 的方法。这些方法可能会创建同步版本的镜像,这些同步版本会在当前线程上执行相同的操作。
•该类还可能有一个 “[方法名称]completed” 事件,监听异步方法的结果。
•它可能会有一个 “[方法名称]asynccancel”(或只是 cancelasync)方法,用于取消正在进行的异步操作。
参数和返回值都没有特殊规定,按照业务需求而定
典型应用
以请求一个url为例
public class eap_typical
{
public static void asyncrun()
{
utility.log("asyncrun:start");
//测试网址
string url = http://sports.163.com/nba/;
using (webclient webclient = new webclient())
{
//获取完成情况
webclient.downloadstringcompleted += new downloadstringcompletedeventhandler(webclient_downloadstringcompleted);
webclient.downloadstringasync(new uri(url));
utility.log("asyncrun:download_start");
}
}
static void webclient_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
{
string log = "asyncrun:download_completed";
//获取返回结果
log += "|result_size=" + utility.getstrlen(e.result);
utility.log(log);
}
}
捕获异常
异常信息一般在completed的事件参数中传递的。紧接上面的例子,如果需要获取返回的异常信息,则需要改写一下downloadstringcomleted的方法。
static void webclient_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
{
string log = "asyncrun:download_completed";
if (e.error != null) //可见,在事件的参数传输异常信息
{
//出现异常,就记录异常
log += "|error=" + e.error.message;
}
else
{
//没有出现异常,则记录结果
log += "|result_size=" + utility.getstrlen(e.result);
}
utility.log(log);
}
状态
eap本身并没有维护状态,如果需要的话,应该设置不同的时间响应不同的状态改变;
假设刚才的downloadstringasync,需要增加多几个状态值,可以考虑增加多几个事件。
如
event downloadstringstarted(响应下载刚开始)
event downloadstringpending(响应下载阻塞中)
event downloadstringcancel(响应下载取消时)
等等。
取消操作
按命名规范,如果操作对应有“[方法名称]asynccancel”(或只是 cancelasync)方法,则支持取消操作。
取消的状态捕获,还是以刚才的下载url输出html为例,还是在downloadstringcompleted 获取取消与否的状态。downloadstringcompletedeventargs. cancelled
注意的是,如果用户执行了cancelasync后,在downloadstringcompletedeventargs.error就会获取到对应的异常,此时不要再取downloadstringcompletedeventargs.result。
进度报告
eap没有硬性规定说要支持进度报告,但可以很顺其自然地通过时间响应进度变化。
以当前例子,webclient 就提供了downloadprogresschanged 做进度变化的响应事件。
apm
命名、参数、返回值
apm的编程模式的代码命名有以下特点:
•使用 iasyncresult 设计模式的异步操作是通过名为[begin操作名称] 和 [end操作名称] 的两个方法来实现的,这两个方法分别开始和结束异步操作 操作名称。 例如,filestream 类提供 beginread 和 endread 方法来从文件异步读取字节。 这两个方法实现了 read 方法的异步版本。
•在调用 [begin操作名称] 后,应用程序可以继续在调用线程上执行指令,同时异步操作在另一个线程上执行。 每次调用 [begin操作名称] 时,应用程序还应调用 [end操作名称] 来获取操作的结果。
典型应用
以请求一个url为例
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.net;
using system.io;
namespace asynctest1.apm
{
public class apmtestrun1
{
public static void asyncrun()
{
utility.log("apmasyncrun:start");
//测试网址
string url = "http://sports.163.com/nba/";
httpwebrequest webrequest = httpwebrequest.create(url) as httpwebrequest;
webrequest.begingetresponse(callback, webrequest);
utility.log("asyncrun:download_start");
}
private static void callback(iasyncresult ar)
{
var source = ar.asyncstate as httpwebrequest;
var response = source.endgetresponse(ar);
using (var stream = response.getresponsestream())
{
using (var reader = new streamreader(stream))
{
string content = reader.readtoend();
utility.log("asyncrun:result_size=" + utility.getstrlen(content));
}
}
}
}
}
委托的异步调用也用的是apm模式,这个方式的强大之处,在于可以使任何方法编程异步调用。
/// <summary>
/// 一个耗时的方法
/// </summary>
private static void caluatemanynumber() {
for (int i = 0; i < 10; i++)
{
thread.sleep(100);
console.writeline("loop==>"+i.tostring());
}
}
/// <summary>
/// 委托,让耗时方法可以异步执行
/// </summary>
public static void asyncdelegate() {
//委托简单的包装了一下方法
action action = caluatemanynumber;
action.begininvoke(delegatecallback, null);
console.writeline("action begin");
}
/// <summary>
/// 异步回调
/// </summary>
/// <param name="ar"></param>
private static void delegatecallback(iasyncresult ar) {
asyncresult asyncresult = ar as asyncresult;
var delegatesource = asyncresult.asyncdelegate as action;
delegatesource.endinvoke(ar);
console.writeline("action end");
}
捕获异常
异常信息要在[end操作名称]中获取。
private static void callback(iasyncresult ar)
{
var source = ar.asyncstate as httpwebrequest;
webresponse response = null;
try
{
response = source.endgetresponse(ar);
}
catch (exception ex) {
utility.log("error:" + ex.message);
response = null;
}
if (response != null)
{
using (var stream = response.getresponsestream())
{
using (var reader = new streamreader(stream))
{
string content = reader.readtoend();
utility.log("asyncrun:result_size=" + utility.getstrlen(content));
}
}
}
}
状态和取消操作、进度报告
apm模式本身不支持状态多样化和取消操作、进度报告。
•基于事件的异步编程设计模式 (eap,event-based asynchronous pattern)
•异步编程模型(apm,asynchronous programming model)
•基于任务的编程模型(tap,task-based asynchronous pattern)
基于任务的异步模式 (tap) 是基于 system.threading.tasks 命名空间的 task 和 task<tresult>,用于表示任意异步操作。 tap 是新开发的建议异步设计模式,之后再讨论。
先总结一下旧有的2种模式:eap、apm。
从以下几个方面,看这2种异步编程方式的异同:
•命名、参数、返回值
•典型应用
•捕获异常
•状态
•取消操作
•进度报告
eap
命名、参数、返回值
eap的编程模式的代码命名有以下特点:
•将有一个或多个名为 “[方法名称]async” 的方法。这些方法可能会创建同步版本的镜像,这些同步版本会在当前线程上执行相同的操作。
•该类还可能有一个 “[方法名称]completed” 事件,监听异步方法的结果。
•它可能会有一个 “[方法名称]asynccancel”(或只是 cancelasync)方法,用于取消正在进行的异步操作。
参数和返回值都没有特殊规定,按照业务需求而定
典型应用
以请求一个url为例
复制代码 代码如下:
public class eap_typical
{
public static void asyncrun()
{
utility.log("asyncrun:start");
//测试网址
string url = http://sports.163.com/nba/;
using (webclient webclient = new webclient())
{
//获取完成情况
webclient.downloadstringcompleted += new downloadstringcompletedeventhandler(webclient_downloadstringcompleted);
webclient.downloadstringasync(new uri(url));
utility.log("asyncrun:download_start");
}
}
static void webclient_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
{
string log = "asyncrun:download_completed";
//获取返回结果
log += "|result_size=" + utility.getstrlen(e.result);
utility.log(log);
}
}
捕获异常
异常信息一般在completed的事件参数中传递的。紧接上面的例子,如果需要获取返回的异常信息,则需要改写一下downloadstringcomleted的方法。
复制代码 代码如下:
static void webclient_downloadstringcompleted(object sender, downloadstringcompletedeventargs e)
{
string log = "asyncrun:download_completed";
if (e.error != null) //可见,在事件的参数传输异常信息
{
//出现异常,就记录异常
log += "|error=" + e.error.message;
}
else
{
//没有出现异常,则记录结果
log += "|result_size=" + utility.getstrlen(e.result);
}
utility.log(log);
}
状态
eap本身并没有维护状态,如果需要的话,应该设置不同的时间响应不同的状态改变;
假设刚才的downloadstringasync,需要增加多几个状态值,可以考虑增加多几个事件。
如
event downloadstringstarted(响应下载刚开始)
event downloadstringpending(响应下载阻塞中)
event downloadstringcancel(响应下载取消时)
等等。
取消操作
按命名规范,如果操作对应有“[方法名称]asynccancel”(或只是 cancelasync)方法,则支持取消操作。
取消的状态捕获,还是以刚才的下载url输出html为例,还是在downloadstringcompleted 获取取消与否的状态。downloadstringcompletedeventargs. cancelled
注意的是,如果用户执行了cancelasync后,在downloadstringcompletedeventargs.error就会获取到对应的异常,此时不要再取downloadstringcompletedeventargs.result。
进度报告
eap没有硬性规定说要支持进度报告,但可以很顺其自然地通过时间响应进度变化。
以当前例子,webclient 就提供了downloadprogresschanged 做进度变化的响应事件。
apm
命名、参数、返回值
apm的编程模式的代码命名有以下特点:
•使用 iasyncresult 设计模式的异步操作是通过名为[begin操作名称] 和 [end操作名称] 的两个方法来实现的,这两个方法分别开始和结束异步操作 操作名称。 例如,filestream 类提供 beginread 和 endread 方法来从文件异步读取字节。 这两个方法实现了 read 方法的异步版本。
•在调用 [begin操作名称] 后,应用程序可以继续在调用线程上执行指令,同时异步操作在另一个线程上执行。 每次调用 [begin操作名称] 时,应用程序还应调用 [end操作名称] 来获取操作的结果。
典型应用
以请求一个url为例
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.net;
using system.io;
namespace asynctest1.apm
{
public class apmtestrun1
{
public static void asyncrun()
{
utility.log("apmasyncrun:start");
//测试网址
string url = "http://sports.163.com/nba/";
httpwebrequest webrequest = httpwebrequest.create(url) as httpwebrequest;
webrequest.begingetresponse(callback, webrequest);
utility.log("asyncrun:download_start");
}
private static void callback(iasyncresult ar)
{
var source = ar.asyncstate as httpwebrequest;
var response = source.endgetresponse(ar);
using (var stream = response.getresponsestream())
{
using (var reader = new streamreader(stream))
{
string content = reader.readtoend();
utility.log("asyncrun:result_size=" + utility.getstrlen(content));
}
}
}
}
}
委托的异步调用也用的是apm模式,这个方式的强大之处,在于可以使任何方法编程异步调用。
复制代码 代码如下:
/// <summary>
/// 一个耗时的方法
/// </summary>
private static void caluatemanynumber() {
for (int i = 0; i < 10; i++)
{
thread.sleep(100);
console.writeline("loop==>"+i.tostring());
}
}
/// <summary>
/// 委托,让耗时方法可以异步执行
/// </summary>
public static void asyncdelegate() {
//委托简单的包装了一下方法
action action = caluatemanynumber;
action.begininvoke(delegatecallback, null);
console.writeline("action begin");
}
/// <summary>
/// 异步回调
/// </summary>
/// <param name="ar"></param>
private static void delegatecallback(iasyncresult ar) {
asyncresult asyncresult = ar as asyncresult;
var delegatesource = asyncresult.asyncdelegate as action;
delegatesource.endinvoke(ar);
console.writeline("action end");
}
捕获异常
异常信息要在[end操作名称]中获取。
复制代码 代码如下:
private static void callback(iasyncresult ar)
{
var source = ar.asyncstate as httpwebrequest;
webresponse response = null;
try
{
response = source.endgetresponse(ar);
}
catch (exception ex) {
utility.log("error:" + ex.message);
response = null;
}
if (response != null)
{
using (var stream = response.getresponsestream())
{
using (var reader = new streamreader(stream))
{
string content = reader.readtoend();
utility.log("asyncrun:result_size=" + utility.getstrlen(content));
}
}
}
}
状态和取消操作、进度报告
apm模式本身不支持状态多样化和取消操作、进度报告。
上一篇: JAVA比较两张图片相似度的方法