1. 程式人生 > >async&await的前世今生

async&await的前世今生

amp efault nco void compiler ges -s lis private

async&await=custom IAsyncStateMachine
async&await是IAsyncStateMachine的語法糖

驗證

分別使用async&await和IAsyncStateMachine遍歷一棵樹,查看二者的線程id和線程上下文標識是否相同

數據結構

public class Node
{
    private static List<Node> _nodes = new List<Node>();
    private static int _id = 1;
    public Node()
    {
        this.Id = _id++;
        _nodes.Add(this);
    }

    public int Id { get; }

    public Node Left { get; set; }
    public Node Right { get; set; }

    public bool IsLeaf => this.Left == null && this.Right == null;
    public bool IsTraveled { get; set; } = false;

    public override string ToString()
    {
        return $"{Left?.Id ?? 0}|{this.Id}|{Right?.Id ?? 0}";
    }
}

使用async&await遍歷樹

public static async Task<int> Travle(Node node)
{
    node.IsTraveled = true;
    if (!node.IsLeaf)
    {
        Console.WriteLine("線程id:" + Thread.CurrentThread.ManagedThreadId + "|線程上下文標識:" + Thread.CurrentThread.ExecutionContext.GetHashCode() + ":" + await Travle(node.Left));
        Console.WriteLine("線程id:" + Thread.CurrentThread.ManagedThreadId + "|線程上下文標識:" + Thread.CurrentThread.ExecutionContext.GetHashCode() + ":" + await Travle(node.Right));
    }
    return node.Id;
}

使用IAsyncStateMachine遍歷樹

public static Task<int> StateMechineTravle(Node node)
{
    StateMechine stateMechine = new StateMechine();
    stateMechine.node = node;
    stateMechine.builder = AsyncTaskMethodBuilder<int>.Create();
    stateMechine.state = -1;
    AsyncTaskMethodBuilder<int> next_builder = stateMechine.builder;
    next_builder.Start<StateMechine>(ref stateMechine);
    return stateMechine.builder.Task;
}

這裏StateMechine是實現IAsyncStateMachine接口的一個類

public struct StateMechine : IAsyncStateMachine
{
    public int state;

    public AsyncTaskMethodBuilder<int> builder;

    public Node node;

    private object wrap1;

    private object wrap2;

    private TaskAwaiter<int> awaiter;

    void IAsyncStateMachine.MoveNext()
    {
        int num = this.state;
        int id;
        try
        {
            TaskAwaiter<int> taskAwaiter;
            if (num != 0)
            {
                if (num == 1)
                {
                    taskAwaiter = this.awaiter;
                    this.awaiter = default(TaskAwaiter<int>);
                    this.state = -1;
                    goto IL_1AB;
                }
                this.node.IsTraveled = true;
                if (this.node.IsLeaf)
                {
                    goto IL_20C;
                }
                this.wrap1 = Thread.CurrentThread.ManagedThreadId;
                this.wrap2 = Thread.CurrentThread.ExecutionContext.GetHashCode();
                taskAwaiter = Program.StateMechineTravle(this.node.Left).GetAwaiter();
                if (!taskAwaiter.IsCompleted)
                {
                    this.state = 0;
                    this.awaiter = taskAwaiter;
                    this.builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, StateMechine>(ref taskAwaiter, ref this);
                    return;
                }
            }
            else
            {
                taskAwaiter = this.awaiter;
                this.awaiter = default(TaskAwaiter<int>);
                this.state = -1;
            }
            int arg_CC_0 = taskAwaiter.GetResult();
            taskAwaiter = default(TaskAwaiter<int>);
            object obj = arg_CC_0;
            Console.WriteLine(string.Concat(new object[]
            {
                "線程id:",
                this.wrap1,
                "|線程上下文標識:",
                this.wrap2,
                ":",
                obj
            }));
            this.wrap1 = null;
            this.wrap2 = null;
            this.wrap2 = Thread.CurrentThread.ManagedThreadId;
            this.wrap1 = Thread.CurrentThread.ExecutionContext.GetHashCode();
            taskAwaiter = Program.StateMechineTravle(this.node.Right).GetAwaiter();
            if (!taskAwaiter.IsCompleted)
            {
                this.state = 1;
                this.awaiter = taskAwaiter;
                this.builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, StateMechine>(ref taskAwaiter, ref this);
                return;
            }
            IL_1AB:
            int arg_1BA_0 = taskAwaiter.GetResult();
            taskAwaiter = default(TaskAwaiter<int>);
            obj = arg_1BA_0;
            Console.WriteLine(string.Concat(new object[]
            {
                "線程id:",
                this.wrap2,
                "|線程上下文標識:",
                this.wrap1,
                ":",
                obj
            }));
            this.wrap2 = null;
            this.wrap1 = null;
            IL_20C:
            id = this.node.Id;
        }
        catch (Exception exception)
        {
            this.state = -2;
            this.builder.SetException(exception);
            return;
        }
        this.state = -2;
        this.builder.SetResult(id);
    }

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

結果

輸入1,使用async&await遍歷樹
輸入2,使用IAsyncStateMachine遍歷樹
可以看出,二者一毛一樣
技術分享圖片


技術分享圖片

可見,基於async和await的task不會被多線程調用

示例代碼

https://github.com/snys98/AsyncStateMechineTest

官方資料

https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.iasyncstatemachine?view=netframework-4.7.1

async&await的前世今生