前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友就说到了async, await等新语法。确实,没有异步的多线程是单调的、乏味的,async和await是出现在C#5.0之后,它的出现给了异步并行变成带来了很大的方便。异步编程涉及到的东西还是比较多,本篇还是先介绍下async和await的原理及简单实现。

C#基础系列目录:

之前的那篇 C#基础系列——多线程的常见用法详解 就讲到了多线程new Thread()的方式对于有返回值类型的委托是没有解决方案的,如果需要返回值,必须要依靠异步的方式。了解异步之前,我们先来看看Thread对象的升级版本Task对象:

1、Task对象的前世今生:Task对象是.Net Framework 4.0之后出现的异步编程的一个重要对象。在一定程度上来说,Task对象可以理解Thread对象的一个升级产品。既然是升级产品,那它肯定有他的优势,比如我们上面Thread对象不能解决的问题:对于有返回值类型的委托。Task对象就能简单的解决。

     static void Main(string[] args){Console.WriteLine("执行GetReturnResult方法前的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));var strRes = Task.Run<string>(() => { return GetReturnResult(); });//启动Task执行方法Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.WriteLine(strRes.Result);//得到方法的返回值Console.WriteLine("得到结果后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.ReadLine();}static string GetReturnResult(){Thread.Sleep(2000);return "我是返回值";}

先来看结果:

从结果分析可知在执行var strRes = Task.Run<string>(() => { return GetReturnResult(); })这一句后,主线程并没有阻塞去执行GetReturnResult()方法,而是开启了另一个线程去执行GetReturnResult()方法。直到执行strRes.Result这一句的时候主线程才会等待GetReturnResult()方法执行完毕。为什么说是开启了另一个线程,我们通过线程ID可以看得更清楚:

     static void Main(string[] args){Console.WriteLine("执行GetReturnResult方法前的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));var strRes = Task.Run<string>(() => { return GetReturnResult(); });Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.WriteLine("我是主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);Console.WriteLine(strRes.Result);Console.WriteLine("得到结果后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.ReadLine();}static string GetReturnResult(){Console.WriteLine("我是GetReturnResult里面的线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);Thread.Sleep(2000);return "我是返回值";}

结果:

由此可以得知,Task.Run<string>(()=>{}).Reslut是阻塞主线程的,因为主线程要得到返回值,必须要等方法执行完成。

Task对象的用法如下:

            //用法一Task task1 = new Task(new Action(MyAction));//用法二Task task2 = new Task(delegate{MyAction();});//用法三Task task3 = new Task(() => MyAction());Task task4 = new Task(() =>{MyAction();});task1.Start();task2.Start();task3.Start();task4.Start();

由上可知,Task对象的构造函数传入的是一个委托,既然能传入Action类型的委托,可想而知Action的16中类型的参数又可以派上用场了。于是乎Task对象参数的传递就不用多说了吧。详见 C#基础系列——委托和设计模式(一)里面Action委托的用法。

2、初识 async & await。

        static void Main(string[] args){Console.WriteLine("我是主线程,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);TestAsync();Console.ReadLine();}static async Task TestAsync(){Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));var name = GetReturnResult();Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", await name, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));}static async Task<string> GetReturnResult(){Console.WriteLine("执行Task.Run之前, 线程ID:{0}", Thread.CurrentThread.ManagedThreadId);return await Task.Run(() =>{Thread.Sleep(3000);Console.WriteLine("GetReturnResult()方法里面线程ID: {0}", Thread.CurrentThread.ManagedThreadId);return "我是返回值";});}

结果:

我们来看看程序的执行过程:

由上面的结果可以得到如下结论:

(1)在async标识的方法体里面,如果没有await关键字的出现,那么这种方法和调用普通的方法没什么区别。

(2)在async标识的方法体里面,在await关键字出现之前,还是主线程顺序调用的,直到await关键字的出现才会出现线程阻塞。

(3)await关键字可以理解为等待方法执行完毕,除了可以标记有async关键字的方法外,还能标记Task对象,表示等待该线程执行完毕。所以await关键字并不是针对于async的方法,而是针对async方法所返回给我们的Task。

(4)是否async关键字只能标识返回Task对象的方法呢。我们来试试:

异步方法的返回类型必须为void、Task或者Task<T>类型。也就是说async要么是void,要么和Task关联。

3、除了await关键字,Task对象还有另外一种方式等待执行结果。  

     static async Task TestAsync(){Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));var name = GetReturnResult();Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", name.GetAwaiter().GetResult(), DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));}

这样可以得到相同的结果。

name.GetAwaiter()这个方法得到的是一个TaskAwaiter对象,这个对象表示等待完成的异步任务的对象,并提供结果的参数。所以除了能完成await关键字的等待之外,它还能做一些其他的操作。我们将TaskAwaiter转到定义

public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion{public bool IsCompleted { get; }public TResult GetResult();public void OnCompleted(Action continuation);public void UnsafeOnCompleted(Action continuation);}    

IsCompleted:获取一个值,该值指示异步任务是否已完成。

GetResult():得到执行的结果。这个方法和await关键字效果相同。

OnCompleted():传入一个委托,在任务执行完成之后执行。

UnsafeOnCompleted():计划与此 awaiter 相关异步任务的延续操作。

由此可以看出,await关键字实际上就是调用了TaskAwaiter对象的GetResult()方法。

转载于:https://www.cnblogs.com/Chasel-Chen/p/8984523.html

异步编程初探:async和await相关推荐

  1. 异步编程(async 和 await)

    1.概念 异步编程是一项关键技术,可以直接处理多个核心上的I/O阻塞和并发操作 2.使用场景 对于存在IO密集型(例如从网路请求数据.访问数据库和写入到文件系统)和CPU密集型(例如大量的计算)的任务 ...

  2. 异步编程的 async/await

    async/await 和 Generators + co 的写法非常的相似,只是把用于声明 Generator 函数的 * 关键字替换成了 async 并写在了 function 关键字的前面,把 ...

  3. await原理 js_深入浅出node.js异步编程 及async await原理

    最近看了一些文章对于async await的原理及概念的解析,我觉得很多时候有些不太准确. 尤其是对于async和await会阻塞线程的说法更是有些扯淡了,JS本身就是单线程的语言如果await会阻塞 ...

  4. Boost.Asio基础(五) 异步编程初探

    异步编程 本节深入讨论异步编程将遇到的若干问题.建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的. 为什么须要异步 如前所述,通常同步编程要比异步编程更简单.同步 ...

  5. Unity中的异步编程【1】—— Unity与async 、 await

    新手在Unity里写东西,一个方法的内容如果写复杂了,容易把Uinty写死,就会卡帧,用流行的话来总结就是:在Update里面活生生把天聊死了. 此外,如果新手才入门,不擅长使用消息.事件来进行异步的 ...

  6. 那些年我们一起追逐的多线程(Thread、ThreadPool、委托异步调用、Task/TaskFactory、Parallerl、async和await)

    一. 背景 在刚接触开发的头几年里,说实话,根本不考虑多线程的这个问题,貌似那时候脑子里也有没有多线程的这个概念,所有的业务都是一个线程来处理,不考虑性能问题,当然也没有考虑多线程操作一条记录存在的并 ...

  7. C#:异步编程和线程的使用(.NET 4.5 ),异步方法改为同步执行

    摘自:http://www.codeproject.com/Articles/996857/Asynchronous-programming-and-Threading-in-Csharp-N(葡萄城 ...

  8. C# :异步编程的注意点

    在上一篇<C#:异步编程中的 async 和 await> 中简单介绍了在 C# 中的异步编程以及 async 和 await 编程模型,本文介绍下异步编程的注意事项,主要有以下几个方面. ...

  9. 【转】异步编程系列(Thread、Task、async/await、ajax等)

    序 经过一番努力,我写的异步编程系列也算有头有尾,当然不是说这个系列已经更新完毕,这个头尾只是表示新旧知识点都有简单涉及到,接下去我还会丰富这一系列并且有机会整个小应用(愿景是弄一个开源组件吧,结合s ...

最新文章

  1. JB的测试之旅-上传的mp3文件播放不了
  2. php 抓取https请求数据,PHP + curl 实现 http 或 https 抓取数据:
  3. /usr/local/php-5.2.14/sbin/php-fpm start Starting php_fpm –fpm-config
  4. AAAI 2019 论文解读 | 基于区域分解集成的目标检测
  5. 电脑科学性计算机怎么用,怎么使用科学计算器59 000×(1+r)-2
  6. postman提取返回值
  7. 如何在三个月内获得三年的工作经验
  8. [Asp.net core]使用Polly网络请求异常重试
  9. 计算机应用基础统考模拟练习系统,网教计算机应用基础统考综合模拟练习题(一)...
  10. Jmeter测试计划无法保存或者另存为
  11. 都有哪些查找和下载英文文献的方法?
  12. 关于iOS14 访问相册权限问题
  13. 久邦GOMO总裁朱志在2018校招生交流会分享
  14. Ubuntu 20.04安装微信和QQ,解决微信不能输入中文
  15. 安装 Ubuntu 操作系统步骤教程
  16. SSL Tomcat 双向认证
  17. C++无法在头文件中定义string类数据
  18. python实现任意url转存为图片
  19. CogLTX:应用BERT处理长文本
  20. ROS学习笔记(1)-ROS指令

热门文章

  1. 为什么使用CMD [“nginx“, “-g“, “daemon off;“]启动nginx容器
  2. JAVASE的学习笔记(四)(抽象类,代码块,接口)
  3. 电动汽车典型危险工况及安全检验探讨 | 机动车登记查验
  4. 独角数卡--免费网店搭建详细教程
  5. PHP常用知识点汇总
  6. 调用亚马逊插件keepa数据的API获取产品的历史信息
  7. linux网卡驱动源码分析(一)
  8. 德国跨境电商real.de绑定连连跨境支付收款教程!
  9. 致欧科技深交所上市:市值106亿 第一季营收降11%
  10. iScreen Recorder for Mac(Mac屏幕录制工具)