ETTask
核心代码与C#原生参考
ET | 原生 | 含义 |
---|---|---|
ETTask | Task | |
AsyncETTaskMethodBuilder | AsyncTaskMethodBuilder | 返回任务的异步方法生成器 |
ETTaskCompletionSource | TaskAwaiter | 返回给await的等待者 |
MoveNextRunner | 用于捕获当前执行上下文 |
TASK LIKE需求:
-
async:自定义异步方法生成器
Create()方法
Start()方法
SetResult()方法
Task 自定义Task的Get属性
-
await
自定义Task类需要有GetAwaiter()方法
-
Task:自定义Task
标明特性
[System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(自定义异步方法生成器))]
GetAwaiter()方法返回一个自定义Awaiter
-
Awaiter:自定义Awaiter
需要实现
INotifyCompletion
或ICriticalNotifyCompletion
接口bool IsCompleted {get;}属性
GetResult()方法
OnCompleted()方法
ET自定义Task核心类讲解
关于作用于异步方法返回标识
[AsyncMethodBuilder(typeof(AsyncETTaskMethodBuilder))]
public partial struct ETTask : IEquatable<ETTask>{}
如果希望自定义的Task能够返回参数,需要为其标注[AsyncMethodBuilder(typeof(返回任务的异步方法生成器类))]
标识,如果没有这个标识,async是不会让我们的自定义任务带参返回的,编译器会直接报错。
AsyncETTaskMethodBuilder
返回任务的异步方法生成器

其中Creater、Task、Start、SetResult
方法是刚需
ETTaskCompletionSource
ETTask返回源,真正意义上的Awaiter

ETTask

核心方法为GetAwaiter
,返回Awaiter
对象
其他方法多为Awaiter
与ETTaskCompletionSource
方法的桥接
Awaiter
ETTaskCompletionSource的代理类

await ETTask运行流程
在C#编译器中会识别三个异步关键字
方法外部await
关键字,如果在调用方法前添加了该关键字,编译器会将等待的方法转换成状态机
方法上async
关键字,如果标识了该关键字,编译器则会查找返回类型的特性是否包含AsyncMethodBuilder
,如果返回对象没有该特性,且不是void返回,编辑器会报错
方法内部await
关键字,方法内部没有await
关键字,编译器会将该方法以同步的方式执行
当前面说的三个关键字都存在,且返回类型添加了AsyncMethodBuilder
特性,接下来就可以分析异步的执行流程了,以ETTask为例
-
首先编译器会将等待的方法转换成状态机
-
调用
AsyncMethodBuilder.Type
的Create
方法,创建一个AsyncETTaskMethodBuilder
-
接下来调用
AsyncETTaskMethodBuilder
的Start
方法运作状态机(如果没有方法内部没有
await
关键字,方法将会以同步方式执行,直接跳到第9步然后再从第4步开始执行) -
然后
await
操作符会调用ETTask的GetAwaiter
方法,创建一个Awaiter
返回给状态机 -
状态机调用
Awaiter
的IsCompleted
属性- 如果操作已经以同步方式完成了,属性将返回True
- 继续调用
Awaiter
的GetResult
方法,该方法要么抛出异常,要么返回结果
- 继续调用
- 如果操作以异步方式完成,属性将返回False
- 状态机机调用
Awaiter
的OnCompleted
方法,并向它传递一个委托(引用状态机的MoveNext
方法)
- 状态机机调用
- 如果操作已经以同步方式完成了,属性将返回True
-
现在状态机允许它回到线程原地以执行其他代码。将来某个时候,封装了底层任务的
Awaiter
会在完成时调用委托以执行MoveNext
。 -
当异步方法执行完毕后,会调用
AsyncETTaskMethodBuilder
的SetResult
方法,为Awaiter
写入结果 -
这时
Awaiter
调用GetResult
方法,该方法要么抛出异常,要么返回结果可根据状态机中的字段知道如何到达代码中的正确位置,使方法能从他当初离开的位置继续执行
public async static void Test()
{
await M_ETTask_1();
await M_ETTask_2();
}
static async ETTask M_ETTask_1()
{
return;
}
static ETTask M_ETTask_2()
{
return new ETTask();
}
如果方法加上async
关键字,await
会从AsyncETTaskMethodBuilder
的Task
属性中获取ETTask
如果没有async
关键字,await
会从方法返回获取ETTask
;
ETVoid
ETVoid

可以看到相对于ETTask,ETVoid省略了大部分方法,且在调用Awaiter.IsCompleted属性是必然是返回Ture;
AsyncETVoidMethodBuilder

在AsyncETVoidMethodBuilder
中与AsyncETTaskMethodBuilder
的不同之处在于不再依靠Task
,且SetResult
与SetException
方法都变成了空方法
网友评论