【橙子老哥】c# await关键字底层原理

hello,大家好,又到了橙子老哥的分享时间,希望大家一起学习,一起进步。

废话少说,我们直接开始

前言:

相信大家对await用法肯定很清楚了,这篇文章主要介绍他的原理,因为要看底层,就要看他的il代码了

1:无异步:

首先,我们先看第一种情况

Console.WriteLine("test");

他的IL:

using System;
using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void <Main>$(string[] args)
  {
    Console.WriteLine("test");
  }

  public Program()
  {
    base..ctor();
  }
}

朴实无华,调用了Program下的$方法,该执行什么就是执行什么

2:一个await

Console.WriteLine("test");
await Console.Out.WriteLineAsync("test2");
Console.WriteLine("test3");

他的IL:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

[CompilerGenerated]
internal class Program
{
  [AsyncStateMachine(typeof (Program.<<Main>$>d__0))]
  [DebuggerStepThrough]
  private static Task <Main>$(string[] args)
  {
    Program.<<Main>$>d__0 stateMachine = new Program.<<Main>$>d__0();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.args = args;
    stateMachine.<>1__state = -1;
    stateMachine.<>t__builder.Start<Program.<<Main>$>d__0>(ref stateMachine);
    return stateMachine.<>t__builder.Task;
  }

  public Program()
  {
    base..ctor();
  }

  [DebuggerStepThrough]
  [SpecialName]
  private static void <Main>(string[] args)
  {
    Program.<Main>$(args).GetAwaiter().GetResult();
  }

  [CompilerGenerated]
  private sealed class <<Main>$>d__0 : IAsyncStateMachine
  {
    public int <>1__state;
    public AsyncTaskMethodBuilder <>t__builder;
    public string[] args;
    private TaskAwaiter <>u__1;

    public <<Main>$>d__0()
    {
      base..ctor();
    }

    void IAsyncStateMachine.MoveNext()
    {
      int num1 = this.<>1__state;
      try
      {
        TaskAwaiter awaiter;
        int num2;
        if (num1 != 0)
        {
          Console.WriteLine("test");
          awaiter = Console.Out.WriteLineAsync("test2").GetAwaiter();
          if (!awaiter.IsCompleted)
          {
            this.<>1__state = num2 = 0;
            this.<>u__1 = awaiter;
            Program.<<Main>$>d__0 stateMachine = this;
            this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<<Main>$>d__0>(ref awaiter, ref stateMachine);
            return;
          }
        }
        else
        {
          awaiter = this.<>u__1;
          this.<>u__1 = new TaskAwaiter();
          this.<>1__state = num2 = -1;
        }
        awaiter.GetResult();
        Console.WriteLine("test3");
      }
      catch (Exception ex)
      {
        this.<>1__state = -2;
        this.<>t__builder.SetException(ex);
        return;
      }
      this.<>1__state = -2;
      this.<>t__builder.SetResult();
    }

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

一下子东西变多了,直接劝退很多人,这是个人看的东西吗?其实主要是因为自动生成的代码命名非常的机器,导致看起来比较困难,其实这段代码还是比较清晰的论命名的重要性

我们先从入口看
[DebuggerStepThrough]
  [SpecialName]
  private static void <Main>(string[] args)
  {
    Program.<Main>$(args).GetAwaiter().GetResult();
  }

依旧是Program这个类的方法进入,注意这里其实是个同步方法,因为它使用了.GetAwaiter().GetResult();

所以这里本质上和同步一样,只是编译的时候包了一层而已

我们继续看里面走了什么,Program.$(args)

 Program.<<Main>$>d__0 stateMachine = new Program.<<Main>$>d__0();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.args = args;
    stateMachine.<>1__state = -1;
    stateMachine.<>t__builder.Start<Program.<<Main>$>d__0>(ref stateMachine);
    return stateMachine.<>t__builder.Task;
    

看起来确实很懵逼,那我们把命名一换

StateMachine stateMachine = new StateMachine();
stateMachine.TaskMethodBuilder = AsyncTaskMethodBuilder.Create();
stateMachine.args = args;
stateMachine.State = -1;
stateMachine.TaskMethodBuilder.Start<StateMachine>(ref stateMachine);
return stateMachine.TaskMethodBuilder.Task;

怎么样?只是换了一个名称,这个逻辑就很清晰了
1:创建了一个状态机
2:AsyncTaskMethodBuilder创建一个任务
3:放入args参数
4:设置起始状态-1
5:Start运行状态机
6:返回Task

所以这一块的代码是固定的,目的是为了生成一个状态机,我们看看状态机<$>d__0,这个里面做什么的

一样的,我们去掉多余代码,并修改命名,try catch也去掉,假设它一定成功

   int num1 = this.State;

      TaskAwaiter awaiter;
      int num2;
      if (num1 != 0)
      {
        Console.WriteLine("test");
        awaiter = Console.Out.WriteLineAsync("test2").GetAwaiter();
        if (!awaiter.IsCompleted)
        {
          this.State = num2 = 0;
          this.Awaiter = awaiter;
          Program.StateMachine stateMachine = this;
          this.TaskMethodBuilder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.StateMachine(ref awaiter, ref stateMachine);
          return;
        }
      }
      else
      {
        awaiter = this.Awaiter;
        this.Awaiter = new TaskAwaiter();
        this.State = num2 = -1;
      }
      awaiter.GetResult();
      Console.WriteLine("test3");
      
      this.State = -2;
      this.TaskMethodBuilder.SetResult();

这样看,是不是就很清晰了
1:由于初始状态为-1,肯定先执行num1 != 0,第一个异步方法之前的代码
2:通过awaiter.IsCompleted判断是否完成,没有完成修改State为0直接返回
3:第二次进入的时候,又会走else里的内容,因为状态为0继续改成-1,回到起点,直到等到下次状态机机再判断到完成为止
4: 如果awaiter.IsCompleted已经完成,就走Console.WriteLine(“test3”);设置状态为-2,设置结果走出状态机

到这里基本就是awit状态机做的事情了
结束了吗?远远没有

3:三个await

Console.WriteLine("test");
await Console.Out.WriteLineAsync("test2");
Console.WriteLine("test3");
await Console.Out.WriteLineAsync("test4");
Console.WriteLine("test5");
await Console.Out.WriteLineAsync("test6");
Console.WriteLine("test7");

它的IL

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

[CompilerGenerated]
internal class Program
{
  [AsyncStateMachine(typeof (Program.<<Main>$>d__0))]
  [DebuggerStepThrough]
  private static Task <Main>$(string[] args)
  {
    Program.<<Main>$>d__0 stateMachine = new Program.<<Main>$>d__0();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.args = args;
    stateMachine.<>1__state = -1;
    stateMachine.<>t__builder.Start<Program.<<Main>$>d__0>(ref stateMachine);
    return stateMachine.<>t__builder.Task;
  }

  public Program()
  {
    base..ctor();
  }

  [DebuggerStepThrough]
  [SpecialName]
  private static void <Main>(string[] args)
  {
    Program.<Main>$(args).GetAwaiter().GetResult();
  }

  [CompilerGenerated]
  private sealed class <<Main>$>d__0 : IAsyncStateMachine
  {
    public int <>1__state;
    public AsyncTaskMethodBuilder <>t__builder;
    public string[] args;
    private TaskAwaiter <>u__1;

    public <<Main>$>d__0()
    {
      base..ctor();
    }

    void IAsyncStateMachine.MoveNext()
    {
      int num1 = this.<>1__state;
      try
      {
        TaskAwaiter awaiter1;
        int num2;
        TaskAwaiter awaiter2;
        TaskAwaiter awaiter3;
        switch (num1)
        {
          case 0:
            awaiter1 = this.<>u__1;
            this.<>u__1 = new TaskAwaiter();
            this.<>1__state = num2 = -1;
            break;
          case 1:
            awaiter2 = this.<>u__1;
            this.<>u__1 = new TaskAwaiter();
            this.<>1__state = num2 = -1;
            goto label_8;
          case 2:
            awaiter3 = this.<>u__1;
            this.<>u__1 = new TaskAwaiter();
            this.<>1__state = num2 = -1;
            goto label_11;
          default:
            Console.WriteLine("test");
            awaiter1 = Console.Out.WriteLineAsync("test2").GetAwaiter();
            if (!awaiter1.IsCompleted)
            {
              this.<>1__state = num2 = 0;
              this.<>u__1 = awaiter1;
              Program.<<Main>$>d__0 stateMachine = this;
              this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<<Main>$>d__0>(ref awaiter1, ref stateMachine);
              return;
            }
            break;
        }
        awaiter1.GetResult();
        Console.WriteLine("test3");
        awaiter2 = Console.Out.WriteLineAsync("test4").GetAwaiter();
        if (!awaiter2.IsCompleted)
        {
          this.<>1__state = num2 = 1;
          this.<>u__1 = awaiter2;
          Program.<<Main>$>d__0 stateMachine = this;
          this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<<Main>$>d__0>(ref awaiter2, ref stateMachine);
          return;
        }
label_8:
        awaiter2.GetResult();
        Console.WriteLine("test5");
        awaiter3 = Console.Out.WriteLineAsync("test6").GetAwaiter();
        if (!awaiter3.IsCompleted)
        {
          this.<>1__state = num2 = 2;
          this.<>u__1 = awaiter3;
          Program.<<Main>$>d__0 stateMachine = this;
          this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<<Main>$>d__0>(ref awaiter3, ref stateMachine);
          return;
        }
label_11:
        awaiter3.GetResult();
        Console.WriteLine("test7");
      }
      catch (Exception ex)
      {
        this.<>1__state = -2;
        this.<>t__builder.SetException(ex);
        return;
      }
      this.<>1__state = -2;
      this.<>t__builder.SetResult();
    }

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

当await的数量达到3个及以上,if的结构还会变成switch+goto
不得不说,用goto之后,代码就开始跳转起飞了,论goto慎用

这里来看,其实道理是一样的,每当一个await完成之后,状态就改为下一步的状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值