异步编程

概念

异步编程核心为异步操作,该操作一旦启动将在一段时间内完成。所谓异步,关键是实现了两点:(1)正在执行的此操作,不会阻塞原来的线程(2)一旦启动的此操作,可以继续执行其他任务。当该操作完成时,将调用回调函数来通知该操作已经结束。

【注】:本人一直以为同步和异步都属于多线程的范畴,到今天才明白完全错误,异步和多线程是属于不同范畴,多线程和异步是并发的两种形式,并行处理和线程同步是多线程的两种形式,这是我当前的理解,不知是否有误,文中若有错误,请园友拍砖并指正,初次学习难免有误,望海涵!

那么问题来了,为什么说异步编程高效呢?首先得了解"IO操作的DMA(Direct Memory Access)模式"即直接内存访问,是一种不经过CPU而直接经过内存数据存储的数据交换模式。通过DMA的数据交换几乎可以不损耗CPU的资源。而CLR提供的异步编程模型正是充分利用了硬件的DMA功能来缓解CPU的压力。

通过async和await关键字实现异步编程

 一般使用方法:在方法声明上加上async关键字,它的目的是使得方法内的关键字await生效(为了保持向后兼容,同时引入了这两个关键字),如果async方法有返回值,返回Task<T>,若没有则返回Task,返回这些Task的目的是通知主程序异步方法的结束。下面我们通过这两个关键字用例子来介绍几本用法!

 1 async Task DoSomethingAsync()
 2 {
 3 int val = 13;
 4 // 异步方式等待1 秒
 5 await Task.Delay(TimeSpan.FromSeconds(1));
 6 val *= 2;
 7 // 异步方式等待1 秒
 8 await Task.Delay(TimeSpan.FromSeconds(1));
 9 Trace.WriteLine(val);
10 }

在winform中程序中,添加一个按钮和label文本,此按钮的点击事件代码为:

1         private void btnSync_Click(object sender, EventArgs e)
2         {
3             DoSomethingSync();
4             label1.Text = "Async Done";
5         }

【问题1】当点击此按钮时先执行完异步方法后输出26,再执行label1.Text=“Aysnc Done”?答案是NO!因为async在开始时是以同步方式执行 ,在其方法内部由于await关键字的存在则会执行一个异步等待!但是在此之前,它首先检查该操作是否已经完成,若完成,则继续以同步方式继续运行!否则则会暂停异步方法,并返回,遗留下这个未完成的Task。一段时间后操作完成,该异步方法恢复运行!是不是没太理解?通俗点说就是,当触发点击事件时,先执行异步方法,此时会在线程池中新起一个工作线程,但是不会阻塞主线程的运行,所以此时会返回一个异步方法中遗留的而未完成的任务,先执行下面一句label1.Text="Async Done",直到该任务完成输出26!

【问题2】如果将上述事件写成如下,结果又会怎样??结论就是先执行完异步方法输出26,然后再执行label1.Text=“Aysnc Done!

        private async void btnSync_Click(object sender, EventArgs e)
        {
            await DoSomethingSync();
            label1.Text = "Async Done";
        }

这个相当于async嵌套了,点击触发该异步事件,执行异步方法DoSomethinSync,所以会新起一个工作线程,不影响主线程的运行,但是此时主线程就是该异步事件,则先执行完该方法后输出26再执行输出文本label1.Text = "Async Done";

所以通过上面得出await关键字的作用:在线程池中新起一个将被执行的工作线程Task,当要执行IO操作时则会将工作线程归还给线程池,因此await所在的方法不会被阻塞。当此任务完成后将会执行该关键字之后代码!

关于异步方法async

一个async方法是有多个同步执行的程序块组成,每个同步执行的的程序块由await隔离!所以鉴于此,每个同步程序块都会试图在原始的上下文中恢复运行,也就是说如果UI线程中调用上述DoSomethinSync方法,则会在UI线程中运行,如果在线程池中调用,则会在线程池的线程中运行!这当然不是我们想要的结果,我们需要的是在调用的线程中运行,同时也要避免这种错误的行为。

对于上述异步方法在异步等待中只需这样修改即可 Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); 对于ConfigureAwait为true时就是将你调用的方法返回到原始的上下文中运行!如此设置后这将在调用的线程中运行。

 

关于任务Task

 (1)需要CPU实际执行命令,创建此类计算的任务时,使用Task.Run,若需按照特定的计划进行则用TaskFactory.StartNew

 (2)需要基于通知(notification)事件的任务和大部分需要IO操作时,使用TaskCompletionSource<T>

总结

(1)在异步编程需要注意的地方

    【1】如果使用了async异步方法最好就一直使用它,再调用返回结束返回的Task对象避免使用Task.Wait或者Task<T>.Result方法,因为极容易造成死锁。

    【2】不要用void 作为async 方法的返回类型! async 方法可以返回void,但是这仅限于编写事件处理程序。一个普通的async方法如果有返回值返回Task<T>否则则会编译出错,如果没有返回值,要返回Task,而不是void!

    【3】在核心库代码中一直使用ConfigureAwait。在外围的用户界面代码中,只在需要时才恢复上下文。

(2)参考资料

    【1】C#并发编程经典实例

    【2】园子一位园友在C#并发编程经典实例上的标注,实在找不到园友链接了,在此表示感谢

 

时间: 2024-12-22 14:16:17

异步编程的相关文章

对 ASP.NET 异步编程的一点理解

本来这篇博文想探讨下异步中的异常操作,但自己在做异步测试的时候,又对 ASP.NET 异步有了新的认识,可以说自己之前对异步的理解还是有些问题,先列一下这篇博文的三个解惑点: async await 到底是什么鬼??? 异步操作中发生异常,该如何处理? 异步操作中发生异常(有无 catch throw 情况),Application_Error 会不会捕获? 之前测试过异步中的同步(很多种情况),这次我们把测试代码写更复杂些(异步中再进行异步),代码如下: [Route("")]  [

Javascript异步编程的4种方法

你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推. 这种模式的好处是实现起来比较简单,执行环境相对单纯:坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行.常见的浏 览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其

C#编程总结(六)异步编程

1.什么是异步? 异步操作通常用于执行完成时间可能较长的任务,如打开大文件.连接远程 计算机或查询数据库.异步操作在主应用程序线程以外的线程中执行.应用程序调用方法异步执行某个 操作时,应用程序可在异步方法执行其任务时继续执行. 2.同步与异步的区别 同步 (Synchronous):在执行某个操作时,应用程序必须等待该操作执行完成后才能继续执行. 异 步(Asynchronous):在执行某个操作时,应用程序可在异步操作执行时继续执行.实质:异步操作, 启动了新的线程,主线程与方法线程并行执行

如何设计一门编程语言(八) 异步编程和CPS变换

关于这个话题,其实在(六)里面已经讨论了一半了.学过Haskell的都知道,这个世界上很多东西都可以用monad和comonad来把一些复杂的代码给抽象成简单的.一看就懂的形式.他们的区别,就像用js做一个复杂的带着几层循环的动画,直接写出来和用jquery的"回调"写出来的代码一样.前者能看不能用,后者能用不能看.那有没有什么又能用又能看的呢?我目前只能在Haskell.C#和F#里面看到.至于说为什么,当然是因为他们都支持了monad和comonad.只不过C#作为一门不把&quo

Generator与异步编程概述

在<深入浅出Node.js>的第4章里,笔者深入地介绍了当前盛行在Node和前端JavaScript中的几种异步编程的解决方案,唯独对Generator的解决方案没有介绍.但随着Node版本的升级和ECMAScript harmony的特性不断得到支持,在0.11版本中,我们可以通过启用--harmory参数让V8支持Generator.最近Connect/Express背后的开发团队也将精力转移到新的库和框架上,这个核心库和框架就是co和koa,它们最主要的特点主要就是基于ECMAScrip

Asp.Net异步编程知识

写在前面的话,很久没有写Blog了,不对,其实一致就没有怎么写过.今天有空,我也来写一篇Blog 随着.Net4.5的推出,一种新的编程方式简化了异步编程,在网上时不时的也看到各种打着Asp.Net异步编程的口号,如何提高性能,如何提高吞吐率! 好多文章都说得不清楚,甚至是错误的.只看到了一些表现,混淆概念.希望这篇文章能够能够对一部分人理解Asp.net异步编程模型. 1基础知识,谈一个初学者不容易理解的基础知识,这个基础知识,很不基础的哦 先看这个代码 ThreadPool.GetMaxTh

Windows 8 Store Apps学习(45) 多线程之异步编程: IAsyncAction

多线程之异步编程: IAsyncAction, IAsyncOperation 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithProgress, IAsyncOperationWithProgress 介绍 重新想象 Windows 8 Store Apps 之 异步编程 IAsyncAction - 无返回值,无进度值 IAsyncOperation - 有返回

Windows 8 Store Apps学习(44) 多线程之异步编程

多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 介绍 重新想象 Windows 8 Store Apps 之 异步编程 经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例 1.使用经典的异步编程模型(IAsyncResult)实现一个支持异步操作的类 Thread/Async/ClassicAsync.cs /*

C#基础学习 —— 异步编程篇 (二)

基于事件的异步模式是比 IAsyncResult 模式更高级的一种异步编程模式,也被用在更多的场合.对于相对简单的应用程序可以直接用 .Net 2.0 新增的 BackgroundWorker 组件来很方便的实现,对于更复杂的异步应用程序则需要自己实现一个符合基于事件的异步模式的类.这两者对我都是新东西,先从简单的入手,下一篇里我再去尝试复杂类模型的实现 模式概述 支持基于事件的异步模式的类会有若干个 MethodNameAsync 方法表示开始异步操作,并有对应的 MethodNameComp

用 Groovy+Jetty 快速实现 Web 异步编程

为什么要异步编程 在现在大规模高并发的 WEB 应用中,由于硬件及网络的限制,I/O 处理速度相当较慢,往往 成为 WEB 系统的性能瓶颈.Node.js 通过非阻塞的 IO 和事件驱动很好的缓解了 Web 服务器在高并发时的资源占用,极大 的提高了 WEB 服务器对高并发的处理能力.同时 Node.js 带来的轻量快捷的异步编程给 WEB 开发带来了一股清新的空气 .那么对于广大的 Java 开发者来说,是否可以实现类似的 WEB 开发呢,答案是肯定的.利用 Groovy 动态语言.Jetty