不得不说的异步编程

1、什么是异步编程?

异步编程就是把耗时的操作放进一个单独的线程中进行处理(该线程需要将执行进度反映到界面上)。由于耗时操作是在另外一个线程中被执行的,所以它不会堵塞主线程。主线程开启这些单独的线程后,还可以继续执行其他操作(例如窗体绘制等)。

异步编程可以提高用户体验,避免在进行耗时操作时让用户看到程序“卡死”的现象。

2、异步编程模型(APM)

APM是Asynchronous Programming Mode的缩写,即异步编程模型的意思,它允许程序用更少的线程去执行更多的操作。在.NET Framework中,要分辨某个类是否实现了异步编程模型,主要就是看该类是否实现了返回类型为IAsyncResult接口的BeginXXX方法和EndXXX方法。

由于委托类型定义了BeginInvoke和EndInvoke方法,所以委托类型都实现了异步编程模型。

2.1 Beginxxx方法--开始执行异步操作

在需要获取文件中的内容时,我们通常会使用FileStream的同步方法Read进行读取,该同步方法的定义为:

public override int Read(byte[] array,int offset,int count)

当使用上面的方法读取大文件的内容时,会出现堵塞UI线程,导致在文件内容没有读取完成之前,用户不能对窗体进行任何操作(包括关闭应用程序),这时窗体就会出现无法响应的情况。

为了解决这个问题,微软早在.NET 1.0的时候就提出了异步编程模型,并为FileStream类提供了异步模式的方法实现,即BeginRead方法。该方法会异步地执行读取操作,并返回实现了IAsyncResult接口的对象(该对象存储这异步操作的信息)。

下面给出了BeginRead方法的定义,我们可以从中找出它与同步方法Read的区别:

public override IAsyncResult BeginRead(byte[] array,int offset,int numBytes,AsyncCallback userCallback,Object stateObject)

从以上的异步方法的定义可以看出,该异步方法的前面3个参数与同步方法Read一致,后两个参数userCallback和StateObject则是同步方法所不具备的。userCallback表示异步操作完成后需要回调的方法,该方法必须匹配AsyncCallback委托类型;stateObject则代表传递给回调方法的对象,在回调方法中,可以通过查询IAsyncResult接口的AsyncState属性来读取该对象。该异步方法之所以不会堵塞UI线程,是因为它在被调用后,会立即把控制权交还给调用线程(如果是UI线程调用了该方法,则就将控制权返回给UI线程),然后由另一个线程去执行文件读取操作。

2.2 Endxxx方法--结束异步操作

每次调用Beginxxx方法后,应用程序还需调用Endxxx方法来获取操作返回的结果。Beginxxx方法所返回的,是实现了IAsyncResult接口的对象,该对象并非相应的同步方法返回的结果。此时还需要调用Endxxx方法来结束异步操作,并向该方法传递Beginxxx所返回的对象。Endxxx方法返回的类型与同步方法相同,如FileStream的EndRead方法会返回一个Int32类型,代表从文件流中实际读取的字节数。

Endxxx方法有许多中方式调用,但有一种是最常用的,即使用AsyncCallback委托来指定操作完成时要调用的方法,在回调方法中调用Endxxx方法来获得异步操作返回的结果。

 1 static void Main()
 2 {
 3     SynchronizationContext sc=SynchronizationContext.Current;
 4     AsyncMethodCaller methodCaller=new AsyncMethodCaller(DownLoadFileAsync);
 5     method.BeginInvoke(txtUrl.Text.Trim(),GetResult,null);
 6 }
 7 private static void GetRsult(IAsyncResult result)
 8 {
 9     AsyncMethodCaller caller=(AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;
10     string returnstring=call.EndInvoke(result);
11 }

3、异步编程模型(EAP)

虽然前面的异步编程可以解决执行耗时操作时界面无法响应的问题,但APM也同样存在这一些明显的问题,如不支持对异步操作的取消以及不能提供下载进度报告等。然而对于桌面应用程序而言,进度报告和取消操作的功能是必不可少的,所以微软在.NET 2.0 发布时又提出了一个新的异步编程模型--基于事件的异步模型,即EAP(Event-based Asynchronous Pattern)。

实现了EAP的类具有一个或多个以Async为后缀的方法,以及对应的Completed事件,并且这些类支持异步方法的取消和进度报告。在.NET类库中,只有部分类实现了EAP,共17个。在这17个类中,开发过程中使用最多的莫过于BackgroundWorker类了。

经常使用的属性为:

CancellationPending:用来指示应用程序是否已请求取消后台操作;

IsBusy:指示异步操作是否正在运行;

WorkReportProgress:只是BackgrounWorker能否报告进度;

WorkerSupportsCancellation:指示BackgroundWoker是否支持异步取消操作;

经常使用的方法为:

CancelAsync:请求取消异步操作;

ReportProgress:用于引发ProgressChanged事件;

RunWorkAsync:调用后开始执行异步操作;

经常使用到的3个事件为:

DoWork:调用RunWokerAsync时触发的事件;

ProgressChanged:调用ReportProgress时触发的事件,程序会在该事件中进行进度报告的更新;

RunWorkerCompleted:当异步操作已完成、被取消或引发异常时被触发。

这种方法已经很少用到了,所以这里就不详细介绍了。

4、TAP又是什么?

前面介绍了.NET提供的两种异步编程模式,分别为.NET 1.0中的APM和.NET 2.0中的EAP。虽然这两种异步编程模式可以实现多数情况下的异步编程,但是它们在MSDN文档上都被标注为了不推荐使用的实现方式,因为在.NET 4.0中,微软又提供了更简单的异步编程实现方式--TAP,基于任务的异步模式。

该模式主要使用System.Threading.Tasks命名空间中的Task<T>类来实现异步编程,所以在采用TAP之前,首先要引入System.Threading.Tasks命名空间。

基于任务的异步模式(TAP,Task-based Asynchronous Pattern)只使用一个方法就能表示异步操作的开始和完成,而APM却需要Beginxxx和Endxxx两个方法分别表示开始和结束,EAP则要求具有以Async为后缀的方法和一个或多个事件。在基于任务的异步模式中,只需要一个以TaskAsync为后缀的方法,通过向该方法传入CancellationToken参数,我们就可以很好地完成异步编程了。而且,还可以通过IProgress<T>接口来实现进度报告的功能。总体来说,使用TAP会减少我们的工作量,是代码更加简洁。

1 Task task=new Task(()=>{.......});
2 task.Start();

5、让异步编程So easy——C# 5.0中的async和await

虽然.NET 1.0和.NET 2.0和.NET 4.0都对异步编程做了很好的支持,微软也逐渐地使用异步编程变得简单,但微软觉得现有的工作还不够,它希望使异步编程的开发过程更为简化,所以在.NET 4.5中,微软又提出了async和await两个关键字来支持异步编程。

这也是目前.NET Framework中最简单的异步编程实现方式,因为使用这个两个关键字进行异步编程,思考方式和实现同步编程时的完全一样。

async和await关键字不会让调用方法运行在新线程中,而是将方法分割成多个片段(片段的界限出现在方法内部使用await关键字的位置处),并使其中一些片段可以异步运行。await关键字处的代码片段是在线程池线程上运行的,而整个方法的调用确实同步的。所以,使用此方式编程不用考虑跨线程访问UI控件的问题,从而大大降低了异步编程的出错率。

时间: 2024-10-11 09:50:43

不得不说的异步编程的相关文章

全面解析C#中的异步编程

当我们处理一些长线的调用时,经常会导致界面停止响应或者IIS线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一种完全不同的编程思想,对于习惯了同步编程的开发者来说,在开发过程中难度更大,可控性不强是它的特点. 在.NET Framework5.0种,微软为我们系统了新的语言特性,让我们使用异步编程就像使用同步编程一样相近和简单,本文中将会解释以前版本的Framework中基于回调道德异步编程模型的一些限制以

.net 异步编程async &amp; await关键字的思考

C# 5.0引入了两个关键字 async和await,这两个关键字在很大程度上帮助我们简化了异步编程的实现代码,而且TPL中的task与async和await有很大的关系 思考了一下异步编程中的async & await关键字,对两个关键字尤其是await关键字一直很迷糊,因此深入思考了一下.首先借助的示例是:[你必须知道的异步编程]C# 5.0 新特性--Async和Await使异步编程更简单这是博客园一个大牛写的,自己也一直关注这个大神,不得不说,博客园大神很多,而且氛围也很好.我引入了其中

.net异步编程の-------异步编程模型(APM)

术语解释: APM               异步编程模型, Asynchronous Programming Model EAP                基于事件的异步编程模式, Event-based Asynchronous Pattern TAP                基于任务的异步编程模式, Task-based Asynchronous Pattern 一.异步编程 APM即异步编程模型的简写(Asynchronous Programming Model),大家在写代

异步编程模型(APM)

一.概念 APM即异步编程模式的简写(Asynchronous Programming Model).大家在写代码的时候或者查看.NET 的类库的时候肯定会经常看到和使用以BeginXXX和EndXXX类似的方法,其实你在使用这些方法的时候,你就再使用异步编程模型来编写程序.NET Framework很多类也实现了该模式,同时我们也可以自定义类来实现该模式,(也就是在自定义的类中实现返回类型为IAsyncResult接口的BeginXXX方法和EndXXX方法),另外委托类型也定义了BeginI

Python Twisted网络编程框架与异步编程入门教程

原作出处:twisted-intro-cn 作者:Dave 译者:杨晓伟 luocheng likebeta 转载声明:版权归原作出处所有,转载只为让更多人看到这部优秀作品合集,如果侵权,请留言告知 感 谢:感谢 杨晓伟 luocheng likebeta 为国内Twisted Coder做的里程碑级贡献 其 它:能访问到Github的童鞋,请访问出处链接.因为出处排版相当棒! 1.Twisted理论基础 2.异步编程初探与reactor模式 3.初次认识Twisted 4.由twisted支持

利用 Python yield 创建协程将异步编程同步化

在 Lua 和 Python 等脚本语言中,经常提到一个概念: 协程.也经常会有同学对协程的概念及其作用比较疑惑,本文今天就来探讨下协程的前世今生. 首先回答一个大家最关心的问题:协程的好处是什么? 通俗易懂的回答: 让原来要使用 异步 + 回调 方式写的非人类代码,可以用看似同步的方式写出来. 1.回顾同步与异步编程 同步编程即线性化编程,代码按照既定顺序执行,上一条语句执行完才会执行下一条,否则就一直等在那里. 但是许多实际操作都是CPU 密集型任务和 IO 密集型任务,比如网络请求,此时不

探索Javascript 异步编程

在我们日常编码中,需要异步的场景很多,比如读取文件内容.获取远程数据.发送数据到服务端等.因为浏览器环境里Javascript是单线程的,所以异步编程在前端领域尤为重要. 异步的概念 所谓异步,是指当一个过程调用发出后,调用者不能立刻得到结果.实际处理这个调用的过程在完成后,通过状态.通知或者回调来通知调用者. 比如我们写这篇文字时点击发布按钮,我们并不能马上得到文章发布成功或者失败.等待服务器处理,这段时间我们可以做其他的事情,当服务器处理完成后,通知我们是否发布成功. 所谓同步,是指当一个过

JavaScript异步编程

在一年前初学js的时候,看过很多关于异步编程的讲解.但是由于实践经验少,没有办法理解的太多,太理论的东西也往往是看完就忘. 经过公司的三两个项目的锻炼,终于对js异步编程有了比较具体的理解.但始终入门较浅,在这里就当是给自己一个阶段性的总结. 在异步编程中,一条语句的执行不能依赖上一条语句执行完毕的结果,因为无法预测一条语句什么时候执行完毕,它与代码顺序无关,语句是并发执行的. 例如以下代码:     1 $.get($C.apiPath+'ucenter/padCharge/findMembe

【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就具体看看编译器到底在背后帮我们做了哪些复杂的工作的. 二.同步代码存在的问题 对于同步的代码,大家肯定都不陌生,因为我们平常写的代码大部分都是同步的,然而同步代码却存在一个很严重的问题,例如我们向一个Web服务器发出一个