async&await的前世今生

Posted microex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了async&await的前世今生相关的知识,希望对你有一定的参考价值。

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的前世今生的主要内容,如果未能解决你的问题,请参考以下文章

async await的前世今生

Spring异步核心@Async注解的前世今生

async&await异步请求处理办法

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

多线程async&await