异步函数简介

一般指 async 修饰符声明得、可包含await表达式得方法或匿名函数。

声明方式

异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字。async可以出现在返回值之前的任何位置, 如下示例:

        async public static void GetInfoAsync(){//...
        }public async static void GetInfoAsync(){//...
        }public static async void GetInfoAsync(){//...}

异步方法的返回类型

异步函数的返回类型只能为: void、Task、Task<TResult>。

Task<TResult>: 代表一个返回值T类型的操作。

Task: 代表一个无返回值的操作。

void: 为了和传统的事件处理程序兼容而设计。

await(等待)

await等待的是什么? 可以是一个异步操作(Task)、亦或者是具备返回值的异步操作(Task<TResult>)的值, 如下:

        public async static void GetInfoAsync(){await GetData(); // 等待异步操作, 无返回值await GetData<int>(1); //等待异步操作, 返回值 int
        }static Task GetData(){//...return null;}static Task<T> GetData<T>(int a){//...return null;}

注: await 最终操作的是一个值, 当然, 也可以是无值,  如上GetData() , 否则就是一个 Task<T>  如上:  GetData<T>()

await执行过程

TaskAwaiter 获取执行结果

一般而言, await等待的一个异步操作, 无论是具备返回值还是否, 那么最终都会获得该操作是否已完成、具备返回值得异步操作可以获取他得返回结果。

所以这个时候, TaskAwaiter出现了, 无论是Task、还是Task<TResult>操作, 都具备GetAwaiter() 方法。

用于获取改操作得状态、返回结果, 及部分操作, 如下TaskAwaiter结构:

    //// 摘要://     提供等待异步任务完成的对象。public struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion{//// 摘要://     获取一个值,该值指示是否已完成的异步任务。//// 返回结果://     true 如果任务已完成;否则为 false。//// 异常://   T:System.NullReferenceException://     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。public bool IsCompleted { get; }//// 摘要://     结束异步任务完成之前的等待。//// 异常://   T:System.NullReferenceException://     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。////   T:System.Threading.Tasks.TaskCanceledException://     任务已取消。////   T:System.Exception://     在完成的任务 System.Threading.Tasks.TaskStatus.Faulted 状态。[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]public void GetResult();//// 摘要://     设置时应执行的操作 System.Runtime.CompilerServices.TaskAwaiter 对象停止等待异步任务完成。//// 参数://   continuation://     要在等待操作完成时执行的操作。//// 异常://   T:System.ArgumentNullException://     continuation 为 null。////   T:System.NullReferenceException://     System.Runtime.CompilerServices.TaskAwaiter 对象未正确初始化。
        [SecuritySafeCritical]public void OnCompleted(Action continuation);//// 摘要://     计划程序与此等待异步任务的延续任务操作。//// 参数://   continuation://     要等待操作完成时调用的操作。//// 异常://   T:System.ArgumentNullException://     continuation 为 null。////   T:System.InvalidOperationException://     该等待程序未正确初始化。
        [SecurityCritical]public void UnsafeOnCompleted(Action continuation);}

 接下来, 演示如何通过等待去获取异步操作的返回结果, 如下代码所示:

        public async static void GetInfoAsync(){Task<bool> task = Task.Run<bool>(() =>{Thread.Sleep(10000); //模拟耗时return true;});//以下两种方式bool taskResult1 = await task;  //内部自己执行了GetAwaiter() bool taskResult = task.GetAwaiter().GetResult();  //自己手动执行Awaiter(), 但是阻塞UI       Console.WriteLine(taskResult);
        }

注: 对于一个await表达式, 编译器生成的代码会先调用GetAwaiter(), 然后通过awaiter得成员来等待结果, 所以以上两种方式等效( 不考虑阻塞的情况下)

为了验证以上猜测, 通过反编译工具查看得到如下代码:

编译器最终生成两个密封类, 一个类( <>c )我们展开分析:

<GetInfoAsync>b__1_0()  正是模拟耗时的一个操作委托生成的方法。

        [CompilerGenerated][Serializable]private sealed class <>c{public static readonly Program.<>c <>9 = new Program.<>c();public static Func<bool> <>9__1_0;internal bool <GetInfoAsync>b__1_0(){Thread.Sleep(10000);return true;}}

第二个类 <GetInfoAsync>d__1 分析:

该类分别实现了接口  IAsyncStateMachine 的MoveNext() 与 SetStateMachine() ,另外 注意,

还特别定义了一个 <>t__builder, 先记住他, 下面讲会对他讲到, 为什么编译器生成的代码会默认先调用GetAwaiter()

 1 [CompilerGenerated]
 2         private sealed class <GetInfoAsync>d__1 : IAsyncStateMachine
 3         {
 4             public int <>1__state;
 5             public AsyncVoidMethodBuilder <>t__builder;
 6             private Task<bool> <task>5__1;
 7             private bool <result>5__2;
 8             private bool <>s__3;
 9             private TaskAwaiter<bool> <>u__1;
10             void IAsyncStateMachine.MoveNext()
11             {
12                 int num = this.<>1__state;
13                 try
14                 {
15                     TaskAwaiter<bool> awaiter;
16                     if (num != 0)
17                     {
18                         Func<bool> arg_2F_0;
19                         if ((arg_2F_0 = Program.<>c.<>9__1_0) == null)
20                         {
21                             arg_2F_0 = (Program.<>c.<>9__1_0 = new Func<bool>(Program.<>c.<>9.<GetInfoAsync>b__1_0));
22                         }
23                         this.<task>5__1 = Task.Run<bool>(arg_2F_0);
24                         awaiter = this.<task>5__1.GetAwaiter();
25                         if (!awaiter.IsCompleted)
26                         {
27                             this.<>1__state = 0;
28                             this.<>u__1 = awaiter;
29                             Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = this;
30                             this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<bool>, Program.<GetInfoAsync>d__1>(ref awaiter, ref <GetInfoAsync>d__);
31                             return;
32                         }
33                     }
34                     else
35                     {
36                         awaiter = this.<>u__1;
37                         this.<>u__1 = default(TaskAwaiter<bool>);
38                         this.<>1__state = -1;
39                     }
40                     this.<>s__3 = awaiter.GetResult();
41                     this.<result>5__2 = this.<>s__3;
42                     Console.WriteLine(this.<result>5__2);
43                 }
44                 catch (Exception exception)
45                 {
46                     this.<>1__state = -2;
47                     this.<>t__builder.SetException(exception);
48                     return;
49                 }
50                 this.<>1__state = -2;
51                 this.<>t__builder.SetResult();
52             }
53             [DebuggerHidden]
54             void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
55             {
56             }
57         }

View Code

接下来, 看GetInfoAsync()方法, 这个是自己编写的, 但是实现的细节,最终转换成了编译器执行代码:

        [AsyncStateMachine(typeof(Program.<GetInfoAsync>d__1)), DebuggerStepThrough]public static void GetInfoAsync(){Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = new Program.<GetInfoAsync>d__1();<GetInfoAsync>d__.<>t__builder = AsyncVoidMethodBuilder.Create();<GetInfoAsync>d__.<>1__state = -1;AsyncVoidMethodBuilder <>t__builder = <GetInfoAsync>d__.<>t__builder;<>t__builder.Start<Program.<GetInfoAsync>d__1>(ref <GetInfoAsync>d__); //注意到该代码, 调用了Start(),也许这就是默认实现的地方}

通过查看Start泛型方法的实现, 最终找到了, 该泛型的条件限制于必须实现与 IAsyncStateMachine 接口, 所以通过查看, 该类最终调用了 MoveNext(), 而MoveNext中正

调用了GetAwaiter()。关于Start的实现如下所示:

[SecuritySafeCritical, DebuggerStepThrough, __DynamicallyInvokable]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{if (stateMachine == null){throw new ArgumentNullException("stateMachine");}ExecutionContextSwitcher executionContextSwitcher = default(ExecutionContextSwitcher);RuntimeHelpers.PrepareConstrainedRegions();try{ExecutionContext.EstablishCopyOnWriteScope(ref executionContextSwitcher); stateMachine.MoveNext();}finally{executionContextSwitcher.Undo();}
}

剖析MoveNext

对比IDE中的代码, 如下所示:

总结

await等待的是任务的操作值, 最终返回是异步操作的返回结果。而这一切都是因为编译器创建了一系列复杂的状态机制, 以达到其实现。

转载于:https://www.cnblogs.com/zh7791/p/9951478.html

C# async/await异步编程深入理解相关推荐

  1. @async 默认线程池_.NET Web应用中为什么要使用async/await异步编程?

    布莱恩特:.NET Core开发精选文章目录,持续更新,欢迎投稿!​zhuanlan.zhihu.com 前言 1.什么是async/await? await和async是.NET Framework ...

  2. 同步方法 调用异步防范_.NET Web应用中为什么要使用async/await异步编程?

    布莱恩特:.NET Core开发精选文章目录,持续更新,欢迎投稿!​zhuanlan.zhihu.com 前言 1.什么是async/await? await和async是.NET Framework ...

  3. Python 3.5将支持Async/Await异步编程

    根据Python增强提案(PEP) 第0492号, Python 3.5将通过async和await语法增加对协程的支持.该提案目的是使协程成为Python语言的原生特性,并"建立一种普遍. ...

  4. Async await 异步编程说明

    希望在编程上有些许提高所以 最近连续2篇博客都在说明多线程和异步编程的使用,异步和多线程之间区别请自行百度,因为理解不是特别透彻就不在叙述以免误导大家,这里写下新研究整理 task  和 await ...

  5. Async和Await异步编程的原理

    1. 简介 从4.0版本开始.NET引入并行编程库,用户能够通过这个库快捷的开发并行计算和并行任务处理的程序.在4.5版本中.NET又引入了Async和Await两个新的关键字,在语言层面对并行编程给 ...

  6. async And await异步编程活用基础

    async And await异步编程活用基础 原文:async And await异步编程活用基础 好久没写博客了,时隔5个月,奉上一篇精心准备的文章,希望大家能有所收获,对async 和 awai ...

  7. promise用法_JavaScript中的async/await的用法和理解

    昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...

  8. async awit 异步调用的理解及应用

    async awit 异步调用的理解及应用 async 是"异步"的简写,而 await 可以认为是 async wait 的简写.所以应该很好理解 async 用于申明一个 fu ...

  9. Microsoft.Bcl.Async 使用总结--在.NET Framework 4.5项目上使用.NET Framework 4.5版本及以上版本才可以使用C# 5中的async/await异步特

    正常情况下async/await异步特性,只能在.NET Framework 4.5以上的版本才可以使用,那如果想在.NET Framework 4使用C# 5中的异步特性怎么办呢?还好有一个开源的类 ...

最新文章

  1. 专访趋势科技CEO陈怡桦:病毒行业需要反省
  2. 知乎真的一天不如一天了吗?
  3. [shell基础]——sed命令
  4. Js获取当前页面URL各种参数
  5. python中排序从小到大_从Python看排序:冒泡排序
  6. python编写ATM类_Python中编写类的各种技巧和方法
  7. mongodb连接认证失败
  8. PopTip View
  9. Windows 7(server 2008) 下直接硬盘安装 Ubuntu 10.04成为双系统的方法
  10. 常见的各种人提出的理论
  11. TCP、UDP、IP头部结构
  12. 阿里巴巴“新六脉神剑”背后的故事
  13. 用Python做一个价值数万的市场调查报告程序,分分钟完成工作
  14. Linux下批量把GDK编码的文章转化为UTF-8编码的文章以及“iconv: 未知 xxx 处的非法输入序列”错误处理
  15. 利用闲置笔记本电脑搭建linux服务器并布置自己的网站
  16. 【苹果CMS技术教程】苹果CMSV10怎么更换模板
  17. Vue之小目标列表实现
  18. 华为面试手撕真题【最长不重复子串】
  19. brew cask安装软件提示:Error: Unknown command: cask
  20. sfc流程图怎么画_GX Works2编程软件SFC流程图编写

热门文章

  1. 企业研发人员配备比例_高新企业研发人员占比多少
  2. Python入门--模块,from,import,自定义模块
  3. OpenGL基础11:空间
  4. 图的绝对中心(bzoj 2180: 最小直径生成树)
  5. bzoj 3631: [JLOI2014]松鼠的新家(LCA+树上差分)
  6. C++ STL 一个简单的stack程序
  7. 有状态容器实践:k8s集成ceph分布式存储
  8. quartus仿真10:74283的基本功能
  9. 贺利坚老师汇编课程37笔记:把六个字符串里的头一个字母改写成大写字母
  10. python生成随机整数