主要是為了看ET框架的ETTask這一節(jié)源碼。所以來梳理一下C# async執(zhí)行邏輯
參考文章:
https://www.cnblogs.com/pangjianxin/p/8710471.html
http://www.itdecent.cn/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篇有點難看,但是不得不看)
早些時候跑的測試代碼:http://www.itdecent.cn/p/b1d55ab05c44
標記了async編譯起創(chuàng)建一個實現(xiàn)IAsyncStateMachine的狀態(tài)機,既然是狀態(tài)機那么肯定 有相應的狀態(tài),這里出現(xiàn)的狀態(tài)有n+2個。n是await出現(xiàn)的次數(shù)。還有-1和-2。-1代表起始。-2代表完成狀態(tài)。
可以被await的對象必須實現(xiàn)一個T GetAwaiter()方法、而T必須實現(xiàn)ICriticalNotifyCompletion(這個接口繼承INotifyCompletion),bool IsCompleted()和TResult GetResult()方法。
具體流程(下面代碼不是我的,也是我網上找的)
執(zhí)行下面這方法
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);
}
下面就是編譯器生成的代碼,網上有人叫骨架代碼啥的
具體就是創(chuàng)建 一個狀態(tài)機,初始化狀態(tài)機的參數(shù)等
利用builder啟動狀態(tài)機(本質調用狀態(tài)機的MoveNext方法)
[AsyncStateMachine(typeof(<MyMethodAsync>d__1))]
private static Task<string> MyMethodAsync(int argument)
{
/將方法實參拷貝到狀態(tài)機的字段上
stateMachine = new <MyMethodAsync>d__1(); stateMachine.argument = argument;
/創(chuàng)建 builder
Task<string> stateMachine.t__builder = AsyncTaskMethodBuilder<string>.Create();
stateMachine.m_state = -1; // 設置狀態(tài)的初始位置 // 開始執(zhí)行狀態(tài)機
/返回狀態(tài)機的 Task
stateMachine.t__builder.Start(ref stateMachine)
; return stateMachine.t__builder.Task;
}

這是狀態(tài)機, 狀態(tài)機具體實現(xiàn)參考這篇文章->https://www.codercto.com/a/42846.html
private sealed class <MyMethodAsync>d__1 : IAsyncStateMachine
大致就講了:
1、骨架函數(shù)中stateMachine.t__builder.Start(ref stateMachine)。調用了MoveNext,狀態(tài)機起始狀態(tài)為-1
2、所以就轉到了case -1:這個分支上了。這時第一個await后面的對象使用GetAwaiter()方法獲得awaiter對象。然后通過這個awaiter對象的IsCompleted來判斷是否執(zhí)行完成了。如果IsCompleted == false。這時將會設置當前狀態(tài)機的狀態(tài)m_state為下一狀態(tài),保存當前awaiter用于將來返回。然后調用t__builder.AwaitUnsafeOnCompleted(ref awaiter1, ref stateMachine);這個方法意思是任務完成后調用MoveNext重返狀態(tài)機。
3、現(xiàn)在任務完成,重返狀態(tài)機了,由2知道m(xù)_state,所以選擇對應分支進入。拿到2中存的awaiter。利用awaiter.GetResult()獲得計算結果。對于第二個await同樣執(zhí)行類似2的過程。最后跳轉到最后分支獲得第二個awaiter的結果。沒有異常的話將MyMethodAsync函數(shù)結果通過t__builder.SetResult(result);返回出去。外部通過GetResult()得到結果
補充:
.Net中Task和Task<Result>是future類型(代表會在將來完成的操作)。Awaitable可等待對象
在設置完任務完成后的延續(xù)builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.Maind__0>(ref awaiter,ref stateMachine);后。此時將會根據(jù)awaiter的類型進行不同的情況有如下幾種情況:
- TaskAwaiter 2、ConfiguredTaskAwaitable 3、ValueTask 4、Task-Like 5、不去捕捉上下文直接調用awaiter.UnsafeOnCompleted(box.MoveNextAction);
- Task默認會捕捉SynchronizationContext 不為null時將會Post。為null時(控制臺程序SynchronizationContext = null)將會看看是否定義了TaskScheduler,如果沒有就會被丟到線程池中