深入理解C#中的异步(一)——APM模式EAP模式

1 使用异步编程的原因

同步编程,服务器在响A服务的数据库读取,网页请求或者文件请求(这里我们统称为IO操作),如果延迟很大,此时如果来了B服务的IO请求,可能无法及时响应(阻塞),此时异步编程模式(非阻塞)应运而生。

异步编程模式是为了避免性能瓶颈并增强你的应用程序的总体响应能力。

2 异步编程模式

2.1 APM模式

APM(Asynchronous Programming Model) 是 net 1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法.

2.1.1 APM模式示例代码

    class Program
{
static void Main(string[] args)
{
Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
WebResponseHandler handler = new WebResponseHandler(WebContentLength.GetResult);
//IAsyncResult: 异步操作接口(interface)
//BeginInvoke: 委托(delegate)的一个异步方法的开始
IAsyncResult result = handler.BeginInvoke( null, null);
Console.WriteLine("继续做别的事情。");
//异步操作返回
Console.WriteLine(handler.EndInvoke(result));
Console.ReadKey();
}
}
public delegate string WebResponseHandler();
public class WebContentLength
{
public static string GetResult()
{
var client = new WebClient();
var content = client.DownloadString(new Uri("http://cnblogs.com"));
return "网页字数统计:"+content.Length;
}
}

2.1.2 执行结果

备注:APM又是建立在委托之上的。Net Core中的委托 不支持异步调用,也就是 BeginInvoke 和 EndInvoke 方法,即现代异步编程模型中,官方不推荐此模型。此例子使用 .Net FrameWork4.7框架。

2.1.3 APM回调例子

当异步请求响应完成之后,会自动去调用回调方法,将网页字数统计结果打印。

    class Program
{
static void Main(string[] args)
{
Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
WebResponseHandler handler = new WebResponseHandler(WebContentLength.GetResult);
//异步操作接口(注意BeginInvoke方法的不同!)
IAsyncResult result = handler.BeginInvoke( new AsyncCallback(CalllBack), "AsycState:OK");
Console.WriteLine("继续做别的事情。");
Console.ReadKey();
}
static void CalllBack(IAsyncResult result)
{
WebResponseHandler handler = (WebResponseHandler)((AsyncResult)result).AsyncDelegate;
Console.WriteLine(handler.EndInvoke(result));
Console.WriteLine(result.AsyncState);
}
}
public delegate string WebResponseHandler();
public class WebContentLength
{
public static string GetResult()
{
var client = new WebClient();
var content = client.DownloadString(new Uri("http://cnblogs.com"));
return "网页字数统计:" + content.Length;
}
}

备注:可以看出此种回调方式与人的思维逻辑相违背,当在回调函数中存在二级三级回调时,代码可读性变差,编程会变得比平常要困难一些。

2.1.4 执行结果

2.2 EAP模式

EAP(Event-based Asynchronous Pattern)基于事件的异步模式是 .net 2.0提出的,EAP异步编程算是C#对APM的一种补充,让异步编程拥有了一系列状态事件。实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告和报告结果。然而.net中并不是所有的类都支持EAP。

当我们使用EAP模式进行异步编程时,需要满足以下2个条件:

  1. 要进行异步的方法其方法名应该以XXXAsync结尾
  2. 要有一个名为XXXCompleted的事件监听异步方法的完成
  3. 可增加一个CancelAsync方法用于取消正在执行的异步方法(可选)

备注:当调用基于事件的EAP模式的类的XXXAsync方法时,就开始了一个异步操作,并且基于事件的EAP模式是基于APM模式之上的。EAP 是在 .NET Framework 2.0 版中引入的,在 winform,silverlight或者wpf变成中经常用到。

2.2.1 EAP模式编程示例1

    class Program
{
static void Main(string[] args)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += Wc_DownloadStringCompleted;
wc.DownloadStringAsync(new Uri("http://www.baidu.com"));
Console.WriteLine("执行其他任务。");
Console.ReadKey();
}
private static void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
Console.WriteLine("网页字数统计:" + e.Result.Length);
}
}

2.2.2 执行结果

总结:此示例代码的编程模式有没有种似曾相识的感觉。没错,winform,wpf等的点击事件,网络库的接收方法中采用事件驱动型的异步编程模式。

2.2.3 封装一个EAP例子

示例代码如下:

Work类,如下代码使用了了事件驱动型异步编程模式,并且对APM模式进行了封装。

    /// <summary>
/// EAP是对APM的封装
/// </summary>
public class Worker
{
public enum WorkerStatus
{
Cancel = 0, Running = 1, Completed = 2
}
public class WorkerEventArgs : EventArgs
{
public WorkerStatus Status { get; set; }
public string Message { get; set; }
}
public Worker()
{
}
public event EventHandler<WorkerEventArgs> OnWorkCompleted;
IAsyncResult asyncResult = null;
Thread thread = null;
public void WorkAsync()
{
Worker _this = this; Action action = () =>
{
thread = Thread.CurrentThread;
Thread.Sleep(1000);
Console.WriteLine(string.Format("线程:{0},Work Over.", Thread.CurrentThread.ManagedThreadId)); };
//result是IAsyncResult对象,此处无用
//当action委托完成调用之后,会调用如下回调方法。
asyncResult = action.BeginInvoke((result) =>
{
WorkerEventArgs e = null;
try
{
action.EndInvoke(result);
}
catch (ThreadAbortException ex)
{
e = new WorkerEventArgs() { Status = WorkerStatus.Cancel, Message = "异步操作被取消" };
}
if (null != _this.OnWorkCompleted)
{
_this.OnWorkCompleted.Invoke(this, e);
}
},this);
}
public void CancelAsync()
{
if (null != thread)
thread.Abort();
}
}

winform调用例子

异步嗲用WorkAsync,完成之后,事件异步调用WorkOver方法,并传入EventArgs参数。

    public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Worker worker;
private void btnStart_Click(object sender, EventArgs e)
{
worker = new Worker();
worker.OnWorkCompleted += WorkOver;
worker.WorkAsync();
Console.WriteLine(string.Format("线程:{0}", Thread.CurrentThread.ManagedThreadId));
} private void btnCancel_Click(object sender, EventArgs e)
{
worker.CancelAsync();
}
private void WorkOver(object sender, Worker.WorkerEventArgs e)
{
if (null != e)
{
if (Worker.WorkerStatus.Cancel == e.Status)
{
MessageBox.Show(e.Message);
}
}
else
{
Console.WriteLine(string.Format("线程:{0},委托回调完成.", Thread.CurrentThread.ManagedThreadId));
}
}
}

2.2.4 执行结果

  • 执行完成

  • 未执行完成提前取消

注意事项(重要):

  1. APM异步编程时,因异步代码执行在单独的线程中,异步代码中出现的异常应该在调用EndXXX时捕获。
  2. EAP异步编程时,因上述同样原因,代码中的异常信息会被传递到Completed事件的EventArgs参数中。

3 代码仓库

本文中的代码

4 下篇

预告:

深入理解C#中的异步(二)——TAP模式(基于Async,Await,Task的异步)


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.cnblogs.com/JerryMouseLi/p/14100496.html

深入理解C#中的异步(一)——APM模式EAP模式的更多相关文章

  1. 深入理解nodejs中的异步编程

    目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promise ...

  2. 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)

    首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...

  3. .Net中的异步编程总结

    一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...

  4. .NET中的异步

    .NET中4种异步方式? ThreadPool.QueueUserworkItem实现 APM模式(就是BeginXXX和EndXXX成对出现.) EAP模式(就是Event based, 准确说来就 ...

  5. 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?

    转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...

  6. 全面理解Javascript中Promise

    全面理解Javascript中Promise 最近在学习Promise的时候,在网上收集了一些资料,发现很多的知识点不够系统,所以小编特意为大家整理了一些自认为 比较好的文章,供大家更好地学习js中非 ...

  7. javascript中的异步 macrotask 和 microtask 简介

    javascript中的异步 macrotask 和 microtask 简介 什么是macrotask?什么是microtask?在理解什么是macrotask?什么是microtask之前,我们先 ...

  8. 【转】简单理解Vue中的nextTick

    前言: Vue中的nextTick涉及到Vue中DOM的异步更新,感觉很有意思,特意了解了一下.其中关于nextTick的源码涉及到不少知识,很多不太理解,暂且根据自己的一些感悟介绍下nextTick ...

  9. 第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

    一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程:所谓的串行编程就是单线程的作用下,按顺序执行.(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程:充分利用多核cpu的 ...

随机推荐

  1. Linux杂谈: 实现一种简单实用的线程池(C语言)

    基本功能 1. 实现一个线程的队列,队列中的线程启动后不再释放: 2. 没有任务执行时,线程处于pending状态,等待唤醒,不占cpu: 3. 当有任务需要执行时,从线程队列中取出一个线程执行任务: ...

  2. haproxy 思考

    通过代理服务器在两个TCP接连之间转发数据是一个常见的需求,然后通常部署的时候涉及到(虚拟)服务器.真实服务器.防护设备.涉及到多个ip地址相关联,改动一个IP就需要修改配置. 比如反向服务器部署的时 ...

  3. binary hacks读数笔记(ld 链接讲解 二)

    这块将介绍一下ld链接命令的具体使用.ld的作用:ld是GNU binutils工具集中的一个,是众多Linkers(链接器)的一种.完成的功能自然也就是链接器的基本功能:把各种目标文件和库文件链接起 ...

  4. mysql权限管理命令

    #创建用户 create user 'songwp' IDENTIFIED BY '1234' #用户授权 GRANT ALL ON DB01.* TO 'songwp' #撤销权限 REVOKE A ...

  5. 剑指offer刷题(算法类_2)

    排序 035-数组中的逆序对(归并排序) 题目描述 题解 代码 复杂度 029-最小的K个数(堆排序) 题目描述 题解 代码 复杂度 029-最小的K个数(快速排序) 题目描述 题解 代码 复杂度 位 ...

  6. day05-类型转换和变量

    1.类型转换概念 java是强类型语言,所以有些运算的时候,需要用到类型转换 类型转换原则:低-->高,byte,short,char-->int-->long-->float ...

  7. MYSQL学习(三) --索引详解

    创建高性能索引 (一)索引简介 索引的定义 索引,在数据结构的查找那部分知识中有专门的定义.就是把关键字和它对应的记录关联起来的过程.索引由若干个索引项组成.每个索引项至少包含两部分内容.关键字和关键 ...

  8. Python_科学计算平台__pypi体系的numpy、scipy、pandas、matplotlib库简介

    1.numpy--基础,以矩阵为基础的数学计算模块,纯数学 存储和处理大型矩阵. 这个是很基础的扩展,其余的扩展都是以此为基础. 快速学习入口 https://docs.scipy.org/doc/n ...

  9. SMBv3远程代码执行漏洞复现(CVE-2020-0796)

    漏洞基本信息 服务器消息块(SMB),是一个网络通信协议,用于提供共享访问到文件,打印机和串行端口的节点之间的网络上.它还提供了经过身份验证的进程间通信机制.SMB的大多数用法涉及运行Microsof ...

  10. iMindMap思维导图中可以插入哪些附件?

    iMindMap(Windows系统)不仅拥有灵活的排版功能,而且还允许用户插入多种附件,丰富思维导图的内容.用户可以为思维导图添加图片.网址.录音等文件,让导图更显生动性.实用性. 将图片.录音等文 ...