.NET中的异步编程 - EAP/APM

从.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模式本身不支持状态多样化和取消操作、进度报告。

[.net 多线程]异步编程模式的更多相关文章

  1. C#多线程和异步(三)——一些异步编程模式

    一.任务并行库 任务并行库(Task Parallel Library)是BCL中的一个类库,极大地简化了并行编程,Parallel常用的方法有For/ForEach/Invoke三个静态方法.在C# ...

  2. 基于任务的异步编程模式,Task-based Asynchronous Pattern

    术语: APM           异步编程模型,Asynchronous Programming Model,其中异步操作由一对 Begin/End 方法(如 FileStream.BeginRea ...

  3. .Net Core自实现CLR异步编程模式(Asynchronous programming patterns)

    最近在看一个线程框架,对.Net的异步编程模型很感兴趣,所以在这里实现CLR定义的异步编程模型,在CLR里有三种异步模式如下,如果不了解的可以详细看MSDN 文档Asynchronous progra ...

  4. 多线程异步编程示例和实践-Thread和ThreadPool

    说到多线程异步编程,总会说起Thread.ThreadPool.Task.TPL这一系列的技术.总结整理了一版编程示例和实践,分享给大家. 先从Thread和ThreadPool说起: 1. 创建并启 ...

  5. 多线程异步编程示例和实践-Task

    上篇博文中,我们介绍了Thread和ThreadPool: 多线程异步编程示例和实践-Thread和ThreadPool 本文中我们继续,说一下TPL(Task Parallel Library, 简 ...

  6. .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)

    本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...

  7. C#中的异步编程模式

    异步编程模型(APM) 基于事件的异步编程模式 基于任务的异步模式 Async Await编程 关于C#,可以看看Learning Hard的博客

  8. 二、基于事件的异步编程模式(EAP)

    一.引言 在上一个专题中为大家介绍了.NET 1.0中提出来的异步编程模式--APM,虽然APM为我们实现异步编程提供了一定的支持,同时它也存在着一些明显的问题--不支持对异步操作的取消和没有提供对进 ...

  9. 基于任务的异步编程模式(TAP)的错误处理

    在前面讲到了<基于任务的异步编程模式(TAP)>,但是如果调用异步方法,没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常.因为在异步方法执行出现 ...

随机推荐

  1. Oracle用游标删除重复数据

    CREATE OR REPLACE PROCEDURE PR_MOD_BASE IS cursor c_base IS SELECT MIN(INVENTORY_DATE) IDATE,KUNNR,M ...

  2. U-boot分析与移植(2)----U-boot stage1分析

    我们要生成u-boot.bin文件,它首先依赖于很多.o文件和.lds链接脚本文件 我们只要找到对应的.lds链接脚本文件就可以分析u-boot的启动流程. 1.打开u-boot-1.1.6\u-bo ...

  3. Java面向对象-递归

    Java面向对象-递归 递归,就是程序调用自身,我们讲的是方法递归调用,也就是在方法里自己调用自己: 我们给出一个案例,求阶乘  1*2*3*...*(n-1)*n 我们用非递归和递归方式分别实现下, ...

  4. ado connection string

    Provider=SQLOLEDB.1;Password=123;Persist Security Info=True;User ID=sa;Initial Catalog=mydb;Data Sou ...

  5. 优于jdbc的mybatis框架入门

    1.什么是mybatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架. MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索. MyB ...

  6. 模拟linux的内存分配与回收

    模拟linux的内存分配与回收 要求 通过深入理解内存分配管理的三种算法,定义相应的数据结构,编写具体代码. 充分模拟三种算法的实现过程,并通过对比,分析三种算法的优劣. (1)掌握内存分配FF,BF ...

  7. jquery slideDown效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  8. Idea的基本介绍

    Idea的基本介绍 Idea一般是作为一个Java和Scala的开发工具来使用的,它的使用方法和Eclipse有一些不同,这里记录以下一些基本点. 1.创建项目 创建一个新项目的时候,用户必须选择一个 ...

  9. Nginx静态网站的部署

    静态网站的部署 首先先看一下nginx/conf/nginx.conf 配置文件内的信息: #user nobody; worker_processes 1; #error_log logs/erro ...

  10. AJAX省市县三级联动的实现

    省市县数据 本例子中省市县数据保存在MySQL数据库中,部分数据截图如下: 从数据库中读取数据 导入需要的jar包 连接池配置文件 <c3p0-config> <!-- 默认配置,如 ...