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

异步编程

 

概念

异步编程核心为异步操作,该操作一旦启动将在一段时间内完成。所谓异步,关键是实现了两点:(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#并发编程经典实例上的标注,实在找不到园友链接了,在此表示感谢

 
 
标签: C#并发编程

async和await关键字实现异步编程的更多相关文章

  1. C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)

    https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC ...

  2. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  3. Async 与 Await 关键字研究

    1        Aynsc 和 Await 关键字的研究 在 .NET 4.0 以后,基于 Task 的异步编程模式大行其道,因其大大简化了异步编程所带来的大量代码工作而深受编程人员的欢迎,如果你曾 ...

  4. 异步编程,采用WorkgroupWorker,async和await关键字

    金科玉律:不要在UI线程上执行耗时的操作:不要在除了UI线程之外的其他线程上访问UI控件! NET1.1的BeginInvoke异步调用,需要准备3个方法:功能方法GetWebsiteLength,结 ...

  5. .NET中的async和await关键字使用及Task异步调用实例

    其实早在.NET 4.5的时候M$就在.NET中引入了async和await关键字(VB为Async和Await)来简化异步调用的编程模式.我也早就体验过了,现在写一篇日志来记录一下顺便凑日志数量(以 ...

  6. 浅谈async、await关键字 => 深谈async、await关键字

    前言 之前写过有关异步的文章,对这方面一直比较弱,感觉还是不太理解,于是会花点时间去好好学习这一块,我们由浅入深,文中若有叙述不稳妥之处,还请批评指正. 话题 (1)是不是将方法用async关键字标识 ...

  7. 为什么我们要使用Async、Await关键字

    前不久,在工作中由于默认(xihuan)使用Async.Await关键字受到了很多质问,所以由此引发这篇博文“为什么我们要用Async/Await关键字”,请听下面分解: Async/Await关键字 ...

  8. 【转】.NET 4.5 使用async和await关键字调用异步方法

    async和await关键字是.NET 4.5新增加的异步编程方式,通过使用这两个关键字可以轻松便捷的编写异步方法.使用async关键字声明异步方法,使用await关键字等待和获取异步方法返回的结果. ...

  9. async/await actor promise 异步编程

    Python协程:从yield/send到async/await http://blog.guoyb.com/2016/07/03/python-coroutine/ Async/Await替代Pro ...

随机推荐

  1. ajax方式提交带文件上传的表单,上传后不跳转

    ajax方式提交带文件上传的表单 一般的表单都是通过ajax方式提交,所以碰到带文件上传的表单就比较麻烦.基本原理就是在页面增加一个隐藏iframe,然后通过ajax提交除文件之外的表单数据,在表单数 ...

  2. 在汉澳sinox2014建立ZFS高可靠文件存储系统

    在汉澳sinox2014建立ZFS高可靠文件存储系统 汉澳sinox2014能够用比較小的固态硬盘安装,文件系统能够用zfs系统存放. 请准备一些硬盘,比方三块SCSI硬盘:da0,da1,da2 如 ...

  3. R三星463无线网卡驱动,声音驱动程序,FN快捷键驱动,Easy_Display_Manager

    http://download.csdn.net/detail/u012120447/7568369 当我们重装系统,该卡不能使用,您需要使用快捷键无法使用时, Easy_Display_Manage ...

  4. c# 通过配置自动附加数据库

    using System; using System.Collections.Generic; using System.Windows.Forms; using System.Data.SqlCli ...

  5. IntelliJ IDEA15开发时设置中java complier 的问题

    Error:java: Compilation failed: internal java compiler error set中java complier 设置的问题  ,项目中有人用jdk1.6 ...

  6. Web API Test Client 1.2.0

    使用方法 1 安装 matthewcv.WebApiTestClient 到你的Web API 项目 PM> Install-Package matthewcv.WebApiTestClient ...

  7. LR杂记 - loadrunner各项指标结果分析

    Transactions (用户事务分析) 用户事务分析是站在用户角度进行的基础性能分析. 1 . Transation Sunmmary (事务综述) 对事务进行综合分析是性能分析的第一步,通过分析 ...

  8. 《Linux Device Drivers》第十六章 块设备驱动程序——note

    基本介绍 块设备驱动程序通过主传动固定大小数据的随机访问设备 Linux核心Visual块设备作为基本设备和不同的字符设备类型 Linux块设备驱动程序接口,使块设备最大限度地发挥其效用.一个问题 一 ...

  9. [Aaronyang] 写给自己的WPF4.5 笔记15[AyArc诞生-WPF版本绚丽的环状图,Ay制作,AyWindow强势预览]

    原文:[Aaronyang] 写给自己的WPF4.5 笔记15[AyArc诞生-WPF版本绚丽的环状图,Ay制作,AyWindow强势预览]  我的文章一定要做到对读者负责,否则就是失败的文章  -- ...

  10. 【Andrioid】在Gradle编译时生成一个不同的版本号,动态设置应用程序标题,应用程序图标,更换常数

    写项目的时候常常会遇到下面的情况: 1.须要生成測试版本号和正式版本号的apk 2.測试版本号和正式版本号的URL是不一样的 3.測试版本号和正式版本号的包名须要不一致,这样才干安装到同一部手机上面. ...