.Net填坑,C#中的async,await以及编译器给我们做了什么,后面细化再排版

要点:1.函数增加async之后,就会编译器就会帮我我们生成一个状态机代码

static async  void BBB()
        {
            Console.WriteLine("123");
            
        }

编译器帮助生成的

[AsyncStateMachine(typeof (Program.\u003CBBB\u003Ed__5))]
    [DebuggerStepThrough]
    private static void BBB()
    {
      Program.\u003CBBB\u003Ed__5 stateMachine = new Program.\u003CBBB\u003Ed__5();
      stateMachine.\u003C\u003Et__builder = AsyncVoidMethodBuilder.Create();
      stateMachine.\u003C\u003E1__state = -1;
      stateMachine.\u003C\u003Et__builder.Start<Program.\u003CBBB\u003Ed__5>(ref stateMachine);
    }

AsyncVoidMethodBuilder类型根据async函数返回值生成

private sealed class \u003CBBB\u003Ed__5 : IAsyncStateMachine
    {
      public int \u003C\u003E1__state;
      public AsyncVoidMethodBuilder \u003C\u003Et__builder;

      public \u003CBBB\u003Ed__5()
      {
        base.\u002Ector();
      }

      void IAsyncStateMachine.MoveNext()
      {
        int num = this.\u003C\u003E1__state;
        try
        {
          Console.WriteLine("123");
        }
        catch (Exception ex)
        {
          this.\u003C\u003E1__state = -2;
          this.\u003C\u003Et__builder.SetException(ex);
          return;
        }
        this.\u003C\u003E1__state = -2;
        this.\u003C\u003Et__builder.SetResult();
      }

      [DebuggerHidden]
      void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
      {
      }
    }

直接调用状态机的movenext,程序就直接往下走了。

如果async函数中,带有await,则会根据await 得到的awaiter类型,生成对应的代码

static async void BBB()
    {
        await Task.Delay(1000);
        Console.WriteLine("Hello, World!");
    }
[AsyncStateMachine(typeof (Program.\u003CBBB\u003Ed__1))]
  [DebuggerStepThrough]
  private static void BBB()
  {
    Program.\u003CBBB\u003Ed__1 stateMachine = new Program.\u003CBBB\u003Ed__1();
    stateMachine.\u003C\u003Et__builder = AsyncVoidMethodBuilder.Create();
    stateMachine.\u003C\u003E1__state = -1;
    stateMachine.\u003C\u003Et__builder.Start<Program.\u003CBBB\u003Ed__1>(ref stateMachine);
  }
[CompilerGenerated]
  private sealed class \u003CBBB\u003Ed__1 : IAsyncStateMachine
  {
    public int \u003C\u003E1__state;
    public AsyncVoidMethodBuilder \u003C\u003Et__builder;
    private TaskAwaiter \u003C\u003Eu__1;

    public \u003CBBB\u003Ed__1()
    {
      base.\u002Ector();
    }

    void IAsyncStateMachine.MoveNext()
    {
      int num1 = this.\u003C\u003E1__state;
      try
      {
        TaskAwaiter awaiter;
        int num2;
        if (num1 != 0)
        {
          awaiter = Task.Delay(1000).GetAwaiter();
          if (!awaiter.IsCompleted)
          {
            this.\u003C\u003E1__state = num2 = 0;
            this.\u003C\u003Eu__1 = awaiter;
            Program.\u003CBBB\u003Ed__1 stateMachine = this;
            this.\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.\u003CBBB\u003Ed__1>(ref awaiter, ref stateMachine);
            return;
          }
        }
        else
        {
          awaiter = this.\u003C\u003Eu__1;
          this.\u003C\u003Eu__1 = new TaskAwaiter();
          this.\u003C\u003E1__state = num2 = -1;
        }
        awaiter.GetResult();
        Console.WriteLine("Hello, World!");
      }
      catch (Exception ex)
      {
        this.\u003C\u003E1__state = -2;
        this.\u003C\u003Et__builder.SetException(ex);
        return;
      }
      this.\u003C\u003E1__state = -2;
      this.\u003C\u003Et__builder.SetResult();
    }

    [DebuggerHidden]
    void IAsyncStateMachine.SetStateMachine([Nullable(1)] IAsyncStateMachine stateMachine)
    {
    }
  }

因此像上面的代码,BBB函数中,虽然用了async标记,但是在调用BBB函数的地方,是不能用await的,因为BBB是void,外层函数没东西可以等待,改为下面

static async Task BBB()
    {
        await Task.Delay(1000);
        Console.WriteLine("Hello, World!");
    }

这样外层调用函数可以await BBB()了,其实BBB函数已经两个Task类实例(一个是Task.Delay,一个是AsyncTaskMethodBuilder类提供的,BBB函数中的状态机代码没变)

private static Task BBB()
  {
    Program.\u003CBBB\u003Ed__1 stateMachine = new Program.\u003CBBB\u003Ed__1();
    stateMachine.\u003C\u003Et__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.\u003C\u003E1__state = -1;
    stateMachine.\u003C\u003Et__builder.Start<Program.\u003CBBB\u003Ed__1>(ref stateMachine);
    return stateMachine.\u003C\u003Et__builder.Task;
  }

这样当外层函数调用await BBB()时,返回的AsyncTaskMethodBuilder.Task中的awaiter没有完成,只有BBB函数中状态机完成,才会调用

this.\u003C\u003E1__state = -2;
      this.\u003C\u003Et__builder.SetResult();

然后外层的await中状态机才能获取到BBB函数返回的Task完成的状态,继续执行下去。然后一层套一层继续下去,可以一直等待。

那么如果是带返回值的呢,如下:

static async Task<string> BBB()
    {
        await Task.Delay(1000);
        Console.WriteLine("Hello, World!");
        return "123";
    }

生成核心的movenext代码如下:

void IAsyncStateMachine.MoveNext()
    {
      int num1 = this.\u003C\u003E1__state;
      string result;
      try
      {
        TaskAwaiter awaiter;
        int num2;
        if (num1 != 0)
        {
          awaiter = Task.Delay(1000).GetAwaiter();
          if (!awaiter.IsCompleted)
          {
            this.\u003C\u003E1__state = num2 = 0;
            this.\u003C\u003Eu__1 = awaiter;
            Program.\u003CBBB\u003Ed__1 stateMachine = this;
            this.\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.\u003CBBB\u003Ed__1>(ref awaiter, ref stateMachine);
            return;
          }
        }
        else
        {
          awaiter = this.\u003C\u003Eu__1;
          this.\u003C\u003Eu__1 = new TaskAwaiter();
          this.\u003C\u003E1__state = num2 = -1;
        }
        awaiter.GetResult();
        Console.WriteLine("Hello, World!");
        result = "123";
      }
      catch (Exception ex)
      {
        this.\u003C\u003E1__state = -2;
        this.\u003C\u003Et__builder.SetException(ex);
        return;
      }
      this.\u003C\u003E1__state = -2;
      this.\u003C\u003Et__builder.SetResult(result);
    }

最重要的就是:this.\u003C\u003Et__builder.SetResult(result);
就是说状态机走完了,将后续函数要返回的值,先声明一个string result;,状态走完,设置这个result值,然后传给builder的SetResult方法,内部会调用对应Task的方法来设置结果,这样外层函数await的时候,也能拿到这个结果。

总结:函数标记async后,就会生成状态机代码,而且状态机根据本函数返回值,生成对应的builder,内部可能包含一个可以被等待的对象(Task.GetAwaiter(),返回的对象实现了ICriticalNotifyCompletion接口就算可等待对象),这样外层才能调用await。
async函数内部,使用了await 来等待一个可等待对象时(比如Task),会在状态机中生成,对应的代码,并将awaiter与状态机的movenext函数关联起来,当有任务完成时,会调用awaier的代码来调用movenext代码,再次回到状态机中进行下一步。

ET框架中,实现了自己的ETTask(他本身实现了接口ICriticalNotifyCompletion,所以ETTask.GetAwaiter()返回自身就可以了,且通过接口实现了,状态机moveNext方法与ETTask关联)。同时也实现了ETTask自己的类Builder类ETAsyncTaskMethodBuilder。
内部封装了一个ETTvoid,用途就是使得在ETTASK同步调用中,等待一下自己,然后等待自己的async函数返回ETVoid,对应有AsyncETVoidMethodBuilder,ETTASK中调用Coroutine,会等待自身完成,但是没有后续代码,外层调用ETTASK的地方就不用await了,这样异常也不会丢失。

写的很概括,后面有空再排版与优化这块,先挖坑

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值