返回

ETTask

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

    需要实现INotifyCompletionICriticalNotifyCompletion接口

    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方法是刚需

ETTaskCompletionSourceETTask返回源,真正意义上的Awaiter

ETTask

核心方法为GetAwaiter,返回Awaiter对象

其他方法多为AwaiterETTaskCompletionSource方法的桥接

Awaiter ETTaskCompletionSource的代理类

await ETTask运行流程

在C#编译器中会识别三个异步关键字

方法外部await关键字,如果在调用方法前添加了该关键字,编译器会将等待的方法转换成状态机

方法上async关键字,如果标识了该关键字,编译器则会查找返回类型的特性是否包含AsyncMethodBuilder,如果返回对象没有该特性,且不是void返回,编辑器会报错

方法内部await关键字,方法内部没有await关键字,编译器会将该方法以同步的方式执行

当前面说的三个关键字都存在,且返回类型添加了AsyncMethodBuilder特性,接下来就可以分析异步的执行流程了,以ETTask为例

  1. 首先编译器会将等待的方法转换成状态机

  2. 调用AsyncMethodBuilder.TypeCreate方法,创建一个AsyncETTaskMethodBuilder

  3. 接下来调用AsyncETTaskMethodBuilderStart方法运作状态机

    (如果没有方法内部没有await关键字,方法将会以同步方式执行,直接跳到第9步然后再从第4步开始执行)

  4. 然后await操作符会调用ETTask的GetAwaiter方法,创建一个Awaiter返回给状态机

  5. 状态机调用AwaiterIsCompleted属性

    • 如果操作已经以同步方式完成了,属性将返回True
      • 继续调用AwaiterGetResult方法,该方法要么抛出异常,要么返回结果
    • 如果操作以异步方式完成,属性将返回False
      • 状态机机调用AwaiterOnCompleted方法,并向它传递一个委托(引用状态机的MoveNext方法)
  6. 现在状态机允许它回到线程原地以执行其他代码。将来某个时候,封装了底层任务的Awaiter会在完成时调用委托以执行MoveNext

  7. 当异步方法执行完毕后,会调用AsyncETTaskMethodBuilderSetResult方法,为Awaiter写入结果

  8. 这时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会从AsyncETTaskMethodBuilderTask属性中获取ETTask

如果没有async关键字,await会从方法返回获取ETTask

ETVoid

ETVoid

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

AsyncETVoidMethodBuilder

AsyncETVoidMethodBuilder中与AsyncETTaskMethodBuilder的不同之处在于不再依靠Task,且SetResultSetException方法都变成了空方法

Licensed under CC BY-NC-SA 4.0
0