APM是.NET中异步编程模型的缩写(Asynchronous Programing Model)。

通过异步编程,使得我们的程序可以更加高效的利用系统资源。

主要内容:

  • 一个APM的例子
  • GUI中的APM
  • APM的优劣点
  • AMP使用中的注意事项

1. 一个APM的例子

.Net中的异步模型非常完善,只要看到Begin***者End***方法。基本都是相对***方法的异步调用方式。

(注:***是方法的名称)

所以在.Net中实现一个异步调用是很方便的,下面用个小例子来演示一个异步操作。

首先是同步的方式请求百度搜索10次。(分别搜索1,2,3。。。。10)

public class CLRviaCSharp_21
{static void Main(string[] args){// 用百度分别检索1,2,3。。。9,共检索10次DateTime start = DateTime.Now;string strReq = "http://www.baidu.com/s?wd={0}";for (int i = 0; i < 10; i++){var req = WebRequest.Create(string.Format(strReq, i));// 注意这里的GetResponse是同步方法var res = req.GetResponse();Console.WriteLine("检索 {0} 的结果已经返回!", i);res.Close();}Console.WriteLine("耗用时间:{0}毫秒", TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds);Console.ReadKey(true);}
}

结果如下:总共消耗时间33秒多。

异步的方式如下:

public class CLRviaCSharp_21
{static DateTime start;static void Main(string[] args){// 用百度分别检索1,2,3。。。9,共检索10次start = DateTime.Now;string strReq = "http://www.baidu.com/s?wd={0}";for (int i = 0; i < 10; i++){var req = WebRequest.Create(string.Format(strReq, i));// 注意这里的BeginGetResponse就是异步方法var res = req.BeginGetResponse(ProcessWebResponse, req);}Console.ReadKey(true);}private static void ProcessWebResponse(IAsyncResult result){var req = (WebRequest)result.AsyncState;string strReq = req.RequestUri.AbsoluteUri;using (var res = req.EndGetResponse(result)){Console.Write("检索 {0} 的结果已经返回!\t", strReq.Substring(strReq.Length - 1));Console.WriteLine("耗用时间:{0}毫秒", TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks).TotalMilliseconds);}}}

结果如下:总共消耗的时间应该是下面所有时间中最长的那个,即9.5秒左右。

2. GUI中的APM

异步编程除了在服务端会大量应用,在有GUI的客户端也应用比较多(为了保证客户端的界面不会假死)。

但是Winform或WPF程序中,改变界面元素状态只有通过UI线程,其他线程如果试图改变UI元素,就会抛出异常(System.InvalidOperationException)。

using System;
using System.Windows.Forms;
using System.Net;public class CLRviaCSharp_21
{static void Main(string[] args){MyWindowsForm mf = new MyWindowsForm();mf.ShowDialog();}
}internal class MyWindowsForm : Form
{public MyWindowsForm(){Text = "Click in the window to start a web request";Width = 800;Height = 600;}protected override void OnMouseClick(MouseEventArgs e){// 开始异步web请求Text = "web request initilized";var webreq = WebRequest.Create("http://www.baidu.com");webreq.BeginGetResponse(ProcessWebResponse, webreq);base.OnMouseClick(e);}private void ProcessWebResponse(IAsyncResult result){var req = (WebRequest)result.AsyncState;using (var res = req.EndGetResponse(result)){// SynchronizationContext.Current.Post(updateUI, res);// 这里改变UI元素Form的Text属性,抛出了异常Text = "Content length: " + res.ContentLength;}}
}

那么其他线程如何改变UI元素呢。为了保证UI始终有响应,必须能够让其他线程也能改变UI元素。

答案就在上面代码中抛异常的上面一句代码。利用SynchronizationContext的Current属性来获取UI线程的同步上下文信息。

然后调用其Post方法,异步的更新UI元素。

using System;
using System.Windows.Forms;
using System.Net;
using System.Threading;public class CLRviaCSharp_21
{static void Main(string[] args){MyWindowsForm mf = new MyWindowsForm();mf.ShowDialog();}
}internal class MyWindowsForm : Form
{public MyWindowsForm(){Text = "Click in the window to start a web request";Width = 800;Height = 600;}protected override void OnMouseClick(MouseEventArgs e){// 开始异步web请求Text = "web request initilized";var webreq = WebRequest.Create("http://www.baidu.com");webreq.BeginGetResponse(ProcessWebResponse, webreq);base.OnMouseClick(e);}private void ProcessWebResponse(IAsyncResult result){var req = (WebRequest)result.AsyncState;using (var res = req.EndGetResponse(result)){SynchronizationContext.Current.Post(updateUI, res);}}private void updateUI(object state){var res = (WebResponse)state;// 这里改变UI元素Form的Text属性, updateUI这个函数是由UI线程执行的Text = "Content length: " + res.ContentLength;}
}

这样的实现看着很繁琐,所以《CLR via C#》作者Jeffrey实现了一个小方法(SyncContextCallback)来简化这个步骤。

using System;
using System.Windows.Forms;
using System.Net;
using System.Threading;public class CLRviaCSharp_21
{static void Main(string[] args){MyWindowsForm mf = new MyWindowsForm();mf.ShowDialog();}
}internal class MyWindowsForm : Form
{public MyWindowsForm(){Text = "Click in the window to start a web request";Width = 800;Height = 600;}protected override void OnMouseClick(MouseEventArgs e){// 开始异步web请求Text = "web request initilized";var webreq = WebRequest.Create("http://www.baidu.com");webreq.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webreq);base.OnMouseClick(e);}private void ProcessWebResponse(IAsyncResult result){var req = (WebRequest)result.AsyncState;using (var res = req.EndGetResponse(result)){// 这里改变UI元素Form的Text属性, // 这次是在UI线程执行的,SyncContextCallback中获取了UI线程的同步上下文,// 然后用Post方法调用了ProcessWebResponse函数Text = "Content length: " + res.ContentLength;}}// 大牛Jeffrey实现的SyncContextCallback方法private static AsyncCallback SyncContextCallback(AsyncCallback callback){SynchronizationContext sc = SynchronizationContext.Current;// 如果没有同步上下文,直接返回传入的东西if (sc == null) return callback;// 返回一个委托,这个委托将委托Post到捕捉到的SC中return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);}
}

3. APM的优劣点

上面两个例子,可以看出APM的一些优势,第一个例子说明异步的效率高。第二个GUI的例子说明异步可以增强用户体验。

其实APM的优势总结起来有以下几点:

  1. 资源利用率底(比如I/O并发读写时,线程不必等I/O完了就可以处理其他请求。这样几个线程就可以处理大量请求)
  2. 垃圾回收快(线程不用等待请求的操作完成就回线程池等待了,这时的线程在它们的栈顶,垃圾回收时遍历线程查找根比较快)
  3. 线程少,调试快(调试时,一旦遇到断点就会挂起所有线程。异步可以保证线程尽量少,所以调试时感觉会快)
  4. 使得GUI一直保持响应(上面的GUI例子可以说明)
  5. 并发执行下载,速度快(上面第一个例子可以说明)

当然,任何技术都不是完美的,有其适用的一面,也有其不适用的一面。

了解它的缺点,有时候甚至可以帮助我们更好的使用它。

APM的劣势主要有以下几点:

  1. 必须将代码分成多个回调方法(执行流程不直观)
  2. 避免使用实参和局部变量(实参和局部变量在回调方法中无法访问,记住回调方法在另一个线程中)
  3. 许多C#构造无法使用,比如try/catch/finally,using等(因为没法在一个方法中开始try,再在它的回调方法中完成finally)
  4. 有些功能很难实现,比如多个并发操作协作进行,取消和超时(比如上面例子中的更新GUI元素也很麻烦)

4. AMP使用中的注意事项

使用APM时以下几点需要注意:

  1. 不要提早调用End***方法,在回调函数中再调用End***(如果提早调用,异步操作没有完成,End***会一直等待,此时相当于同步调用)
  2. 调用End***且仅调用一次(异步操作初始化时分配的某些资源,必须调用End***才能释放。第二次调用End***时结果不可预测)
  3. 使用相同的对象调用Begin***方法和End***方法
  4. 在Begin***方法和End***方法中使用ref,out,params标记时需要注意(具体实现方法以后有空再补些例子:))
  5. 不能取消异步I/O操作(启动I/O操作后,控制权交给了I/O相关硬件)
  6. Begin***方法返回引用类型,无法返回值类型
  7. 用于打开文件的Win32 API(CreateFile)暂时没有异步的版本
  8. FileStream类在创建时就决定了是异步还是同步的方式(创建式指定异步标记,即使调用Read,也是通过Sleep来模拟同步。同样,指定了同步标记,调用BeginRead也是模拟的异步)

转载于:https://www.cnblogs.com/wang_yb/archive/2011/11/29/2267790.html

《CLR Via C# 第3版》笔记之(二十一) - 异步编程模型(APM)相关推荐

  1. Android 学习之《第一行代码》第二版 笔记(二十三)Material Design 实战 —— 卡片式布局

    实现基础: Android 学习之<第一行代码>第二版 笔记(二十二)Material Design 实战 -- 悬浮按钮和可交互提示 卡片式布局 卡片式布局是 Materials Des ...

  2. 《Java8实战》读书笔记10:组合式异步编程 CompletableFuture

    <Java8实战>读书笔记10:组合式异步编程 CompletableFuture 第11章 CompletableFuture:组合式异步编程 11.1 Future 接口 (只是个引子 ...

  3. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  4. Slicer学习笔记(二十一)slicer的python接口说明

    Slicer学习笔记(二十一)slicer的python接口说明 1.python接口 1.python接口 slicer package Submodules slicer.ScriptedLoad ...

  5. ElasticSearch学习笔记之二十一 指标聚合

    ElasticSearch学习笔记之二十一 指标聚合 指标聚合 Avg Aggregation Script Value Script Missing value Weighted Avg Aggre ...

  6. VTK学习笔记(二十一)vtk裁剪求截面面积

    VTK学习笔记(二十一)vtk裁剪求界面面积 1.代码 2.CMakeLists.txt 3.运行输出 4.面积正确性验证 4.1.代码 4.2.执行结果 1.代码 #pragma once#incl ...

  7. bootstrap媒体查询类型的值_HTMLCSS学习笔记(二十一)-- 媒体查询 + rem用法

    媒体查询 + rem 计算方法 计算rem方法: 结合媒体查询 -> 随着设备的改变 更改html font-size的值. ​ 媒体查询确定范围?? ​ 移动端设计图 : 640px 750p ...

  8. 机器学习-白板推导系列笔记(二十一)-RBM

    此文章主要是结合哔站shuhuai008大佬的白板推导视频:受限玻尔兹曼机_155min 全部笔记的汇总贴:机器学习-白板推导系列笔记 玻尔兹曼机介绍:白板推导系列笔记(二十八)-玻尔兹曼机 一.背景 ...

  9. NET CLR via c# 第4版笔记 第19章 可空值类型

    System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5;Int32? y = null; ...

最新文章

  1. 轻松恢复误删除的共享文件,DPM2007系列之六
  2. Ubuntu下找不到ttyUSB*问题解决
  3. 全球移动SaaS市场规模5年将增170亿美元
  4. MATLAB Simulink 做BP PID报错:Error :*** during flag=* call must be a real vector of length 3
  5. ubuntu无法安装vscode(visual studio code)如何卸载snap?
  6. servlet的由来
  7. 【报告分享】2020中国教育行业生存实录.pdf(附下载链接)
  8. D. Beautiful numbers
  9. python 字符串子串_Python字符串子字符串
  10. php事务基本要素,数据库事务正确执行的四个基本要素
  11. 使用SQL2005 递归查询结合Row_Number()实现完全SQL端树排序
  12. ios十进制、十六进制字符串,byte,data等之间的转换
  13. 8253/8255/8259相关知识
  14. windows快速全局检索文件工具-Listary
  15. APUE代码运行环境的搭建
  16. 招聘中的热门技术技能:SQL、Java、Python 和 Linux
  17. android京东源码下载,京东商城APP - 源码下载|通讯/手机编程|android开发|源代码 - 源码中国...
  18. vue:无法加载文件..
  19. 南京计算机图书,计算机中心附近图书馆
  20. PS绘画效果滤镜Snap Art 4

热门文章

  1. Base64编码对照表
  2. Linux之/etc/group文件
  3. Webpack 4.X 从入门到精通 - 第三方库(六)
  4. DataFrame.apply()
  5. 几种方法找到整型阵列中的最大值和最小值
  6. GoLang strings包函数用法
  7. 我经历的IT公司面试及离职感受(转)
  8. JS中比較2个字符串内元素的不同(字符1, 字符2, 分隔符可选)
  9. 分享一款好看的城市选择器
  10. linux 下挂载光驱