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完成之后,状态就改为下一步的状态