C# Under the Hood: async/await
https://www.markopapic.com/csharp-under-the-hood-async-await/
Async and await keywords came with C# 5 as a cool new feature for handling asynchronous tasks.
They allow us to specify tasks to be executed asynchronously in an easy and straightforward fashion.
However, some people are mystified by asynchronous programming and are not sure how it actually works.
I will try to give you an insight of the magic that happens under the hood when async and await are used.
Awaiter Pattern
C# language compiles some of the features as a syntactic sugar, which means that certain language features are just conveniences that translate into existing language features.
A lot of those syntactic sugar features expand into patterns.Those patterns are based on method calls, property lookups or interface implementations.
await
expression is one of those syntactic sugar features. It leverages a pattern based on a few method calls. In order for a type to be awaitable, it has to meet the following requirements:
- It has to have the following method:
INotifyCompletion GetAwaiter()
- Besides implementing the INotifyCompletion interface, the return type of the
GetAwaiter
method has to have the following:IsCompleted
property of typebool
GetResult()
method which returnsvoid
If you take a look at Task class, you will see that it meets all the above requirements.
1.被Await的class需要有一个GetAwaiter的方法
2.并且GetAwaiter方法的返回类型,还有3个要求
2.1 必须实现INotifyCompletion接口
2.2 必须有一个IsCompleted属性,类型是bool
2.3 必须有一个GetResult方法,返回值类型是void
So, a type doesn’t even need to implement some specific interface in order to be awaitable.
It just has to have a method with a specific signature. It is similar to duck typing.
If it walks like a duck and it quacks like a duck, then it must be a duck.
In this case it is
If it has certain methods with certain signatures, then it has to be awaitable.
To give you an illustrative example of this, I will create some custom class and make it awaitable.
So, here is my class:
public class MyAwaitableClass { }
When I try to await an object of MyAwaitableClass
type, I get the following error:
static async Task AwaitMyAwaitable() { MyAwaitableClass class1 = new MyAwaitableClass(); await class1; }
Severity Code Description Project File Line Suppression State
Error CS1061 'MyAwaitableClass' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'MyAwaitableClass' could be found (are you missing a using directive or an assembly reference?) async-await-test C:\repository\GitHub\ChuckLu\Test\async-await-test\async-await-test\MainTest.cs 22 Active
Let’s add GetAwaiter
method to our class:
public class MyAwaitableClass { public MyAwaiter GetAwaiter() { return new MyAwaiter(); } } public class MyAwaiter { public bool IsCompleted { get { return false; } } }
We can see that the compiler error changed:
Severity Code Description Project File Line Suppression State
Error CS0535 'MyAwaiter' does not implement interface member 'INotifyCompletion.OnCompleted(Action)' async-await-test C:\repository\GitHub\ChuckLu\Test\async-await-test\async-await-test\MyAwaitableClass.cs 6 Active
Ok, let’s create implement the INotifyCompletion
interface in MyAwaiter
:
public class MyAwaiter : INotifyCompletion { public bool IsCompleted { get { return false; } } public void OnCompleted(Action continuation) { } }
and see what the compiler error looks like now:
Severity Code Description Project File Line Suppression State
Error CS0117 'MyAwaiter' does not contain a definition for 'GetResult' async-await-test C:\repository\GitHub\ChuckLu\Test\async-await-test\async-await-test\MainTest.cs 18 Active
So, we add a GetResult
method and now we have the following:
public class MyAwaitableClass { public MyAwaiter GetAwaiter() { return new MyAwaiter(); } } public class MyAwaiter : INotifyCompletion { public void GetResult() { } public bool IsCompleted { get { return false; } } //From INotifyCompletion public void OnCompleted(Action continuation) { } }
And we can also see that there are no compiler errors,
which means we have made an awaitable type.
Now that we know which pattern does the await
expression leverage, we can take a look under the hood to see what actually happens when we use async
and await
.
Async
For every async method a state machine is generated.
This state machine is a struct that implements IAsyncStateMachine interface from System.Runtime.CompilerServices
namespace. This interface is intended for compiler use only and has the following methods:
MoveNext()
- Moves the state machine to its next state.SetStateMachine(IAsyncStateMachine)
- Configures the state machine with a heap-allocated replica.
Now let’s take a look at the following code:
class Program { static void Main(string[] args) { } static async Task FooAsync() { Console.WriteLine("Async method that doesn't have await"); } }
We have an async method named FooAsync
. You may notice that it lacks await operator, but I left it out for now for the sake of simplicity.
Now let’s take a look at the compiler generated code for this method. I am using dotPeek to decompile the containing .dll file. To see what is going on behind the scenes, you need to enable Show Compiler-generated Code option in dotPeek.
Compiler generated classes usually contain < and > in their names
which are not valid C# identifiers so they don’t conflict with
user-created artifacts.
也可以用dnSpy查看反编译的代码
Let’s take a look what compiler generated for our FooAsync
method:
原文地址:https://www.cnblogs.com/chucklu/p/11411964.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 给你的热图挑选一个合适的渐变色
- 网易云解锁灰色音乐
- AndroidStdio1_4
- 130. 被围绕的区域 Krains 2020-08-11 10:50:01 并查集DFS
- scRNA-seq Clustering(二)
- Apache-Hive 使用MySQL存储Hive的元数据
- 使用TensorFlow创建能够图像重建的自编码器模型
- Qt音视频开发9-ffmpeg录像存储
- AntDesignPro使用electron构建桌面应用
- 跨域资源共享
- AndroidStdio1_3
- Rancher2.4.3 Rest API修改镜像地址
- Python UNIX系统管理指南
- 聊聊dubbo-go的ConsistentHashLoadBalance
- Tacotron2运行笔记