.NET中基于事件的异步模式-EAP

 更新时间:2013年01月02日 09:41:57   作者:  
从.NET 4.5开始,支持的三种异步编程模式:基于事件的异步编程设计模式、异步编程模型、基于任务的编程模型,感兴趣的朋友可以参考下
前言
在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

相关文章

  • .NET中函数Main的使用技巧

    .NET中函数Main的使用技巧

    任何语言开发出来的程序,都会有一个程序入口函数,可能每个语言所使用的程序入口函数名称不一样,但是它们的作用都是一样的,都是被操作系统去调用。那么本文主要总结.NET中的程序入口函数Main使用的小技巧。
    2016-10-10
  • asp.net获取真实ip的方法

    asp.net获取真实ip的方法

    这篇文章主要介绍了asp.net获取真实ip的方法,通过一个简单的自定义函数达到获取用户真实IP的功能,非常简单实用,需要的朋友可以参考下
    2015-07-07
  • 使用asp.net调用谷歌地图api示例

    使用asp.net调用谷歌地图api示例

    这篇文章主要介绍了asp.net调用谷歌地图api的过程,需要注意js引入的先后顺序,需要的朋友可以参考下
    2014-08-08
  • 使用asp.net MVC4中的Bundle遇到的问题及解决办法分享

    使用asp.net MVC4中的Bundle遇到的问题及解决办法分享

    这篇文章主要介绍了使用asp.net MVC4中的Bundle遇到的问题及解决办法,需要的朋友可以参考下
    2014-02-02
  • .NET/C#利用反射调用含ref或out参数的方法示例代码

    .NET/C#利用反射调用含ref或out参数的方法示例代码

    这篇文章主要给大家介绍了关于.NET/C#利用反射调用含ref或out参数的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • asp.net实现文件无刷新上传方法汇总

    asp.net实现文件无刷新上传方法汇总

    本文给大家介绍的是asp.net实现文件无刷新上传的2种方法,分别是使用swfupload插件和uploadify插件,讲述的十分细致全面,附上示例,有需要的小伙伴可以参考下。
    2015-06-06
  • Entity Framework使用Code First的实体继承模式

    Entity Framework使用Code First的实体继承模式

    本文详细讲解了Entity Framework使用Code First的实体继承模式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • .Net集成敏感词组件的步骤

    .Net集成敏感词组件的步骤

    现如今大部分服务都会有用户输入,为了服务的正常运行,很多时候不得不针对输入进行敏感词的检测、替换。如果人工做这样的工作,不仅效率低,成本也高。水弟在这里写了一个让小编姐姐都觉得快的敏感词组件接入示例,不需要依赖第三方服务,只需两分钟即可享受清爽文字。
    2021-05-05
  • datatable行转列示例分享

    datatable行转列示例分享

    这篇文章主要介绍了datatable行转列示例,指定需要转换的表和转换表表头对应旧表字段就可以转换了
    2014-01-01
  • asp.net网站防恶意刷新的Cookies与Session解决方法

    asp.net网站防恶意刷新的Cookies与Session解决方法

    这篇文章主要介绍了asp.net网站防恶意刷新的Cookies与Session解决方法,分别以实例的形式讲述了采用cookie法与session法实现WEB页面防止恶意刷新的技巧,需要的朋友可以参考下
    2014-09-09

最新评论