async await实现原理,反编译源代码解读

发布时间 2023-06-05 10:24:17作者: 留下成长的足迹

1.Task中async await

    public class ThreadAsync
    {
        public static void Show() 
        {
            Console.WriteLine("Show:Start");
            TestTwo();
            Console.WriteLine("Show:End");
        }

        public static async void TestTwo()
        {
            Console.WriteLine("********************  TestTwo ***********************");
            Console.WriteLine("AAA:This is step one: Begain");
            await Task.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("BBB:This is Await_Method_One");
            });
            Console.WriteLine("CCC:This is step between await one and await two");
            await Task.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("DDD:This is Await_Method_Two");
            });
            Console.WriteLine("EEE:This is step End");
        }

    }

执行结果。

2.反编译后看源代码

public class ThreadAsync
{
    [CompilerGenerated]
    private sealed class <TestTwo>d__1 : IAsyncStateMachine
    {
        public int <>1__state;

        public AsyncVoidMethodBuilder <>t__builder;

        private TaskAwaiter <>u__1;

        private void MoveNext()
        {
            int num = <>1__state;
            try
            {
                TaskAwaiter awaiter;
                TaskAwaiter awaiter2;
                if (num != 0)
                {
                    if (num == 1)
                    {
                        awaiter = <>u__1;
                        <>u__1 = default(TaskAwaiter);
                        num = (<>1__state = -1);
                        goto IL_012c;
                    }
                    Console.WriteLine("********************  TestTwo ***********************");
                    Console.WriteLine("AAA:This is step one: Begain");
                    awaiter2 = Task.Run(delegate
                    {
                        Thread.Sleep(1000);
                        Console.WriteLine("BBB:This is Task_Method");
                    }).GetAwaiter();
                    if (!awaiter2.IsCompleted)
                    {
                        num = (<>1__state = 0);
                        <>u__1 = awaiter2;
                        <TestTwo>d__1 stateMachine = this;
                        <>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine);
                        return;
                    }
                }
                else
                {
                    awaiter2 = <>u__1;
                    <>u__1 = default(TaskAwaiter);
                    num = (<>1__state = -1);
                }
                awaiter2.GetResult();
                Console.WriteLine("CCC:This is step between await one and await two");
                awaiter = Task.Run(delegate
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("DDD:This is Task_Method");
                }).GetAwaiter();
                if (!awaiter.IsCompleted)
                {
                    num = (<>1__state = 1);
                    <>u__1 = awaiter;
                    <TestTwo>d__1 stateMachine = this;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
                    return;
                }
                goto IL_012c;
                IL_012c:
                awaiter.GetResult();
                Console.WriteLine("EEE:This is step End");
            }
            catch (Exception exception)
            {
                <>1__state = -2;
                <>t__builder.SetException(exception);
                return;
            }
            <>1__state = -2;
            <>t__builder.SetResult();
        }

        void IAsyncStateMachine.MoveNext()
        {
            //ILSpy generated this explicit interface implementation from .override directive in MoveNext
            this.MoveNext();
        }

        [DebuggerHidden]
        private void SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine)
        {
        }

        void IAsyncStateMachine.SetStateMachine([System.Runtime.CompilerServices.Nullable(1)] IAsyncStateMachine stateMachine)
        {
            //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
            this.SetStateMachine(stateMachine);
        }
    }

    public static void Show()
    {
        Console.WriteLine("Show:Start");
        TestTwo();
        Console.WriteLine("Show:End");
    }

    [AsyncStateMachine(typeof(<TestTwo>d__1))]
    [DebuggerStepThrough]
    public static void TestTwo()
    {
        <TestTwo>d__1 stateMachine = new <TestTwo>d__1();
        stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
        stateMachine.<>1__state = -1;
        stateMachine.<>t__builder.Start(ref stateMachine);
    }
}

3.编译后的TestTwo方法的内容发生了较大的变化。其中多了一个类<TestTwo>d__1, 该类继承接口IAsyncStateMachine,看名字是一个异步状态机,实现MoveNext方法和SetStateMachine方法。

// System.Runtime.CompilerServices.IAsyncStateMachine
using System.Runtime.CompilerServices;

[NullableContext(1)]
public interface IAsyncStateMachine
{
    void MoveNext();

    void SetStateMachine(IAsyncStateMachine stateMachine);
}

 4.查看编译后的TestTwo方法,有4个步骤。

  4.1 创建状态机,即new一个<TestTwo>d__1()对象

 

  4.2 给状态机类的AsyncVoidMethodBuilder属性赋值,(Task有返回是AsyncTaskMethodBuilder<T>对象)

 

  4.3 给状态机的状态<>1__state赋值为-1.后面会看到,第一个await方法,匹配的状态值<>1__state是0,第二个匹配的状态值<>1__state为1

  4.4 启动状态机对象中异步方法AsyncVoidMethodBuilder属性,并把状态机对象作为参数传入。AsyncVoidMethodBuilder.Start(ref sateMachine)方法是触发传入参数stateMachine的MoveNext()方法

 5.进入MoveNext方法,Task.Run().GetAwaiter得到一个TaskAwaiter类

  5.1第一次执行MoveNext,状态值 <>1__state是-1。把TaskAwaiter和当前状态机对象当作参数,传入AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted方法(该方法比较深,大概的意思就是监听Task的OnCompleted事件)。并把状态值<>1__state改为0.当任务完成的时候,会触发传入参数stateMachine的MoveNext方法。

5.2 当第一个await完成后,会继续触发当前状态机对象的MoveNext方法,第二次执行MoveNext,这时<>1__state是0,即num是0.

1.会得到第一个await方法的结果。awaiter2.GetResult();

2.会得到第2个Task的TaskAwaiter对象,然后传入AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine)方法。等待Task.IsCompleted后,继续触发事件,执行当前对象(作为参数stateMachine传入)的MoveNext.

3.把状态值改为1.

 5.3 当第二个await方法执行完毕后,会再次触发MoveNext,状态值<>1__state是1.直接跳到获取第二个await方法获取结果。

 总结,大概就是每执行一步,修改状态<>1__state的值,通过AsyncVoidMethodBuilder类的AwaitUnsafeOnCompleted方法,监听TaskAwaiter的OnCompleted方法,并触发当前的状态机的MoveNext方法。关于AwaitUnsafeOnCompleted的方法的底层调用,日后有时间可以查看源码。AsyncTaskMethodBuilder.cs (dot.net)