深入理解C#中的异步(一)——APM模式EAP模式
深入理解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个条件:
- 要进行异步的方法其方法名应该以XXXAsync结尾
- 要有一个名为XXXCompleted的事件监听异步方法的完成
- 可增加一个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 执行结果
- 执行完成
- 未执行完成提前取消
注意事项(重要):
- APM异步编程时,因异步代码执行在单独的线程中,异步代码中出现的异常应该在调用EndXXX时捕获。
- 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模式的更多相关文章
- 深入理解nodejs中的异步编程
目录 简介 同步异步和阻塞非阻塞 javascript中的回调 回调函数的错误处理 回调地狱 ES6中的Promise 什么是Promise Promise的特点 Promise的优点 Promise ...
- 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)
首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...
- .Net中的异步编程总结
一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...
- .NET中的异步
.NET中4种异步方式? ThreadPool.QueueUserworkItem实现 APM模式(就是BeginXXX和EndXXX成对出现.) EAP模式(就是Event based, 准确说来就 ...
- 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?
转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...
- 全面理解Javascript中Promise
全面理解Javascript中Promise 最近在学习Promise的时候,在网上收集了一些资料,发现很多的知识点不够系统,所以小编特意为大家整理了一些自认为 比较好的文章,供大家更好地学习js中非 ...
- javascript中的异步 macrotask 和 microtask 简介
javascript中的异步 macrotask 和 microtask 简介 什么是macrotask?什么是microtask?在理解什么是macrotask?什么是microtask之前,我们先 ...
- 【转】简单理解Vue中的nextTick
前言: Vue中的nextTick涉及到Vue中DOM的异步更新,感觉很有意思,特意了解了一下.其中关于nextTick的源码涉及到不少知识,很多不太理解,暂且根据自己的一些感悟介绍下nextTick ...
- 第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)
一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程:所谓的串行编程就是单线程的作用下,按顺序执行.(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程:充分利用多核cpu的 ...
随机推荐
- Spider--补充--selenium的使用
# Selenium (firefox) # 1,介绍: # selenium 是一个 web 的自动化测试工具,是一个包,可以支持 C. java.ruby.python.或都是 C# 语言. # ...
- 经典c程序100例==81--90
[程序81] 题目:809*??=800*??+9*??+1 其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数.求??代表的两位数,及809*??后的结果. 1.程序分析: 2.程 ...
- .NET5都来了,你还不知道怎么部署到linux?最全部署方案,总有一款适合你
随着2020进入4季度,.NET5正式版也已经与大家见面了.不过,尽管 .NET Core发布已经有四五年的时间,但到目前为止,依旧有很多.NET开发者在坚守者.NET4,原因不尽相同,但最大的问题可 ...
- martini-新分子的参数化
http://jerkwin.github.io/2016/10/10/Martini%E5%AE%9E%E4%BE%8B%E6%95%99%E7%A8%8BMol/ 对新分子的参数化可以分为两种情况 ...
- IDEA与Eclipse创建struts项目
1.IDEA创建struts项目 这里再构建struts项目是选择jar包出问题了,可以重新配置 创建页面和action配置struts.xml 启动tomcat,浏览器中运行 具体参考: https ...
- Python的ConfigParser模块读取ini配置文件 报错(持续更新总结)
1.ConfigParser.MissingSection什么的错误巴拉巴拉一堆,其实根本上就是没有读到配置文件,然后我去检查了一遍路径,发现没有问题,我是将文件的路径作为一个字符串拼接好传到另一个专 ...
- Jar 和 war 区别
jar包:对于学习java的人来说应该并不陌生.我们也经常使用也一些jar包.其实jar包就是java的类进行编译生成的class文件就行打包的压缩包而已.里面就是一些class文件.当我们自己使用m ...
- 微信小程序生成二维码并且扫码跳转并且携带参数
话不多说,直接上代码,直接把APPID和APPSECRET改成自己的就能用了 <?php header('content-type:text/html;charset=utf-8'); //配置 ...
- webug第六关:这关需要rmb购买哦
第六关:这关需要rmb购买哦 首先登陆,tom 123456 进行抓包改包
- 理解与使用Treiber Stack
目录 背景 名称由来 CompletableFuture源码实现 FutureTask实现 Treiber Stack抽象实现 入栈 出栈 示例 参考 背景 最近在很多JDK源码中都看到了Treibe ...