C# async/await源码执行逻辑梳理

主要是为了看ET框架的ETTask这一节源码。所以来梳理一下C# async执行逻辑
参考文章:
https://www.cnblogs.com/pangjianxin/p/8710471.html
https://www.jianshu.com/p/5dfbccac5c27
https://blog.csdn.net/weixin_43990579/article/details/105417652?spm=1001.2014.3001.5501
https://www.cnblogs.com/raytheweak/tag/C%23/ (这4篇有点难看,但是不得不看)
早些时候跑的测试代码:https://www.jianshu.com/p/b1d55ab05c44

  • 标记了async编译起创建一个实现IAsyncStateMachine的状态机,既然是状态机那么肯定 有相应的状态,这里出现的状态有n+2个。n是await出现的次数。还有-1和-2。-1代表起始。-2代表完成状态。

  • 可以被await的对象必须实现一个T GetAwaiter()方法、而T必须实现ICriticalNotifyCompletion(这个接口继承INotifyCompletion),bool IsCompleted()和TResult GetResult()方法。

  • 具体流程(下面代码不是我的,也是我网上找的)
    执行下面这方法

        static async Task<string> MyMethodAsync(int argument) 
        { 
            var t1 = await GetType1(); 
            var t2 = await GetType2();
            return "Complete"; 
        }

        static async Task<Type> GetType1() 
        { 
            await Task.Run(() => { Console.WriteLine("GetType1"); });
            return typeof(string); 
        }
        static async Task<Type> GetType2() 
        { 
            await Task.Run(() => { Console.WriteLine("GetType2"); });
            return typeof(int); 
        }

下面就是编译器生成的代码,网上有人叫骨架代码啥的
具体就是创建 一个状态机,初始化状态机的参数等
利用builder启动状态机(本质调用状态机的MoveNext方法)

[AsyncStateMachine(typeof(<MyMethodAsync>d__1))] 
private static Task<string> MyMethodAsync(int argument)
{
/将方法实参拷贝到状态机的字段上
  stateMachine = new <MyMethodAsync>d__1(); stateMachine.argument = argument;
/创建 builder 
Task<string> stateMachine.t__builder = AsyncTaskMethodBuilder<string>.Create(); 
stateMachine.m_state = -1; // 设置状态的初始位置 // 开始执行状态机 
/返回状态机的 Task
stateMachine.t__builder.Start(ref stateMachine)
; return stateMachine.t__builder.Task; 
}

这是状态机, 状态机具体实现参考这篇文章->https://www.codercto.com/a/42846.html

private sealed class <MyMethodAsync>d__1 : IAsyncStateMachine

大致就讲了:
1、骨架函数中stateMachine.t__builder.Start(ref stateMachine)。调用了MoveNext,状态机起始状态为-1
2、所以就转到了case -1:这个分支上了。这时第一个await后面的对象使用GetAwaiter()方法获得awaiter对象。然后通过这个awaiter对象的IsCompleted来判断是否执行完成了。如果IsCompleted == false。这时将会设置当前状态机的状态m_state为下一状态,保存当前awaiter用于将来返回。然后调用t__builder.AwaitUnsafeOnCompleted(ref awaiter1, ref stateMachine);这个方法意思是任务完成后调用MoveNext重返状态机。
3、现在任务完成,重返状态机了,由2知道m_state,所以选择对应分支进入。拿到2中存的awaiter。利用awaiter.GetResult()获得计算结果。对于第二个await同样执行类似2的过程。最后跳转到最后分支获得第二个awaiter的结果。没有异常的话将MyMethodAsync函数结果通过t__builder.SetResult(result);返回出去。外部通过GetResult()得到结果

补充:
.Net中Task和Task是future类型(代表会在将来完成的操作)。Awaitable可等待对象
在设置完任务完成后的延续builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.Maind__0>(ref awaiter,ref stateMachine);后。此时将会根据awaiter的类型进行不同的情况有如下几种情况:

  • TaskAwaiter 2、ConfiguredTaskAwaitable 3、ValueTask 4、Task-Like 5、不去捕捉上下文直接调用awaiter.UnsafeOnCompleted(box.MoveNextAction);
  • Task默认会捕捉SynchronizationContext 不为null时将会Post。为null时(控制台程序SynchronizationContext = null)将会看看是否定义了TaskScheduler,如果没有就会被丢到线程池中
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值