.NET中基于事件的异步模式-EAP
程序员文章站
2024-03-05 22:56:37
前言 在c# 5.0中,新增了async await 2个关键字支持异步编程的操作。在讲述这两个关键字之前,我先总结一下.net中的常见的异步编程模型。 异步编程一直是比较...
前言
在c# 5.0中,新增了async await 2个关键字支持异步编程的操作。在讲述这两个关键字之前,我先总结一下.net中的常见的异步编程模型。
异步编程一直是比较复杂的问题,其中要处理多线程之间的数据同步、获取进度、可取消、获取结果、不影响主线程操作、多个任务之间互相不影响等,因此需要设计编程模型去处理此类问题。
从.net 4.5开始,支持的三种异步编程模式:
基于事件的异步编程设计模式 (eap,event-based asynchronous pattern)
异步编程模型(ape,asynchronous programming model)
基于任务的编程模型(tap,task-based asynchronous pattern)
目前新版的.net是偏向于建议使用tap方式进行异步编程,winrt中的异步操作就只有tap的身影,async await关键字也只是支持tap的编程模型。
基于事件的异步模式 - eap
eap的编程模式的代码有以下特点:
将有一个或多个名为 “[方法名称]async” 的方法。这些方法可能会创建同步版本的镜像,这些同步版本会在当前线程上执行相同的操作。
该类还可能有一个 “[方法名称]completed” 事件,监听异步方法的结果。
它可能会有一个 “[方法名称]asynccancel”(或只是 cancelasync)方法,用于取消正在进行的异步操作。
下面是一个符合此模式的类声明示例
public class asyncexample
{
// synchronous methods.
public int method1(string param);
public void method2(double param);
// asynchronous methods.
public void method1async(string param);
public void method1async(string param, object userstate);
public event method1completedeventhandler method1completed;
public void method2async(double param);
public void method2async(double param, object userstate);
public event method2completedeventhandler method2completed;
public void cancelasync(object userstate);
public bool isbusy { get; }
// class implementation not shown.
}
这里虚构的 asyncexample 类有两个方法,都支持同步和异步调用。同步重载的行为类似于方法调用,它们对调用线程执行操作;如果操作很耗时,则调用的返回可能会有明显的延迟。异步重载将在另一个线程上启动操作,然后立即返回,允许在调用线程继续执行的同时让操作“在后台”执行。
system.net.webclient 本身就有很多eap的例子,以它的downloadstring为例,webclient中跟downloadstring相关的方法有:
downloadstring:同步下载字符串资源的方法,此方法阻塞当前线程。
downloadstringasync:使用eap异步编程模式下载字符串资源的方法,此方法不会阻塞当前线程。
downloadstringcompleted:响应异步下载时完成的事件。
downloadprogresschanged:响应异步下载时进度变化。
调用模型示例如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.net;
namespace asynctest1.eap
{
public class eapruntest1
{
public static void asyncrun() {
utility.log("asyncrun:start");
//测试网址
string url = "http://sports.163.com/nba/";
using (webclient webclient = new webclient()) {
//监控下载进度
webclient.downloadprogresschanged += new downloadprogresschangedeventhandler(webclient_downloadprogresschanged);
//监控完成情况
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 += "|cancel=" + e.cancelled.tostring() ;
if (e.error != null)
{
//出现异常,就记录异常
log += "|error=" + e.error.message;
}
else {
//没有出现异常,则记录结果
log += "|result_size=" + utility.getstrlen(e.result);
}
utility.log(log);
}
static void webclient_downloadprogresschanged(object sender, downloadprogresschangedeventargs e)
{
utility.log("asyncrun:download_progress|percent=" + e.progresspercentage.tostring());
}
}
}
运行结果:
2012-12-28 00:39:39:621 asyncrun:start
2012-12-28 00:39:40:377 asyncrun:download_start
2012-12-28 00:39:40:903 asyncrun:download_progress|percent=1
2012-12-28 00:39:40:933 asyncrun:download_progress|percent=3
2012-12-28 00:39:40:933 asyncrun:download_progress|percent=5
2012-12-28 00:39:40:934 asyncrun:download_progress|percent=5
2012-12-28 00:39:40:975 asyncrun:download_progress|percent=9
2012-12-28 00:39:41:068 asyncrun:download_progress|percent=21
2012-12-28 00:39:41:131 asyncrun:download_progress|percent=29
2012-12-28 00:39:41:182 asyncrun:download_progress|percent=37
2012-12-28 00:39:41:298 asyncrun:download_progress|percent=50
2012-12-28 00:39:41:354 asyncrun:download_progress|percent=58
2012-12-28 00:39:41:447 asyncrun:download_progress|percent=74
2012-12-28 00:39:41:489 asyncrun:download_progress|percent=82
2012-12-28 00:39:41:582 asyncrun:download_progress|percent=100
2012-12-28 00:39:41:582 asyncrun:download_progress|percent=100
2012-12-28 00:39:41:614 asyncrun:download_completed|cancel=false|result_size=205568
在c# 5.0中,新增了async await 2个关键字支持异步编程的操作。在讲述这两个关键字之前,我先总结一下.net中的常见的异步编程模型。
异步编程一直是比较复杂的问题,其中要处理多线程之间的数据同步、获取进度、可取消、获取结果、不影响主线程操作、多个任务之间互相不影响等,因此需要设计编程模型去处理此类问题。
从.net 4.5开始,支持的三种异步编程模式:
基于事件的异步编程设计模式 (eap,event-based asynchronous pattern)
异步编程模型(ape,asynchronous programming model)
基于任务的编程模型(tap,task-based asynchronous pattern)
目前新版的.net是偏向于建议使用tap方式进行异步编程,winrt中的异步操作就只有tap的身影,async await关键字也只是支持tap的编程模型。
基于事件的异步模式 - eap
eap的编程模式的代码有以下特点:
将有一个或多个名为 “[方法名称]async” 的方法。这些方法可能会创建同步版本的镜像,这些同步版本会在当前线程上执行相同的操作。
该类还可能有一个 “[方法名称]completed” 事件,监听异步方法的结果。
它可能会有一个 “[方法名称]asynccancel”(或只是 cancelasync)方法,用于取消正在进行的异步操作。
下面是一个符合此模式的类声明示例
复制代码 代码如下:
public class asyncexample
{
// synchronous methods.
public int method1(string param);
public void method2(double param);
// asynchronous methods.
public void method1async(string param);
public void method1async(string param, object userstate);
public event method1completedeventhandler method1completed;
public void method2async(double param);
public void method2async(double param, object userstate);
public event method2completedeventhandler method2completed;
public void cancelasync(object userstate);
public bool isbusy { get; }
// class implementation not shown.
}
这里虚构的 asyncexample 类有两个方法,都支持同步和异步调用。同步重载的行为类似于方法调用,它们对调用线程执行操作;如果操作很耗时,则调用的返回可能会有明显的延迟。异步重载将在另一个线程上启动操作,然后立即返回,允许在调用线程继续执行的同时让操作“在后台”执行。
system.net.webclient 本身就有很多eap的例子,以它的downloadstring为例,webclient中跟downloadstring相关的方法有:
downloadstring:同步下载字符串资源的方法,此方法阻塞当前线程。
downloadstringasync:使用eap异步编程模式下载字符串资源的方法,此方法不会阻塞当前线程。
downloadstringcompleted:响应异步下载时完成的事件。
downloadprogresschanged:响应异步下载时进度变化。
调用模型示例如下:
复制代码 代码如下:
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.net;
namespace asynctest1.eap
{
public class eapruntest1
{
public static void asyncrun() {
utility.log("asyncrun:start");
//测试网址
string url = "http://sports.163.com/nba/";
using (webclient webclient = new webclient()) {
//监控下载进度
webclient.downloadprogresschanged += new downloadprogresschangedeventhandler(webclient_downloadprogresschanged);
//监控完成情况
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 += "|cancel=" + e.cancelled.tostring() ;
if (e.error != null)
{
//出现异常,就记录异常
log += "|error=" + e.error.message;
}
else {
//没有出现异常,则记录结果
log += "|result_size=" + utility.getstrlen(e.result);
}
utility.log(log);
}
static void webclient_downloadprogresschanged(object sender, downloadprogresschangedeventargs e)
{
utility.log("asyncrun:download_progress|percent=" + e.progresspercentage.tostring());
}
}
}
运行结果:
2012-12-28 00:39:39:621 asyncrun:start
2012-12-28 00:39:40:377 asyncrun:download_start
2012-12-28 00:39:40:903 asyncrun:download_progress|percent=1
2012-12-28 00:39:40:933 asyncrun:download_progress|percent=3
2012-12-28 00:39:40:933 asyncrun:download_progress|percent=5
2012-12-28 00:39:40:934 asyncrun:download_progress|percent=5
2012-12-28 00:39:40:975 asyncrun:download_progress|percent=9
2012-12-28 00:39:41:068 asyncrun:download_progress|percent=21
2012-12-28 00:39:41:131 asyncrun:download_progress|percent=29
2012-12-28 00:39:41:182 asyncrun:download_progress|percent=37
2012-12-28 00:39:41:298 asyncrun:download_progress|percent=50
2012-12-28 00:39:41:354 asyncrun:download_progress|percent=58
2012-12-28 00:39:41:447 asyncrun:download_progress|percent=74
2012-12-28 00:39:41:489 asyncrun:download_progress|percent=82
2012-12-28 00:39:41:582 asyncrun:download_progress|percent=100
2012-12-28 00:39:41:582 asyncrun:download_progress|percent=100
2012-12-28 00:39:41:614 asyncrun:download_completed|cancel=false|result_size=205568