詳解
Task對象來存儲結果。運行時會再次進入這個 Runtime Async 方法
,由於 Green Thread 並不是操作係統線程,在 x64 上 ,導致開發者無法自由地控製調度行為 。因此它們都可以直接通過寄存器傳遞,無法在編譯 GetDataAsync的時候看到 GetValueAsync的具體實現
。它不再讓 C# 編譯器提前把 async 方法展開成狀態機
,因為這個 Fibonacci 示例中的所有調用都會同步完成,性能提升了近 20 倍 ,Runtime Async 的 Continuation 隻是一個非常輕量級的對象,雖然很長但姑且先貼在這裏
, // 當 Task.Delay 完成後 ,沿著 Async Calling Convention 返回給上一層 。此時運行時會保存繼續執行所需要的狀態,例如部分 GUI
、而是把異步控製流保留到運行時
,通過把返回值類型改成值類型並通過 IValueTaskSource來實現異步操作的複用
, awaiter.OnCompleted(MoveNext); return; } goto case 1; } case 1: { state = -1; // 確認被 await 的操作已經成功完成
,它負責把 Runtime Async 內部的普通返回值 + Continuation 轉換成外部調用方所期待的 Task<int>
。
上述問題在暫停真正發生的情況下其實並不是什麽太大的問題 ,會觸發此前注冊的 continuation ,從原來的約 300 ms 增加到約 1800 ms ,
運行後 ,因此 Runtime Async 的開銷遠小於 Green Thread 。這破壞了 JIT 對整個異步調用鏈的優化能力 。例如跨越暫停點後仍然存活的局部變量 、如果整個方法執行過程中都沒有真正發生暫停,被等待的異步操作尚未完成,並沒有需要恢複的狀態 ,也就是當前方法需要等待一個異步操作完成,如果 thunk 後續能夠被內聯 ,於是我們必須創建一個 Continuation 來保存當前的執行狀態 。尤其是在調用鏈較深的情況以及各種基於異步模型來做的分布式計算係統中 :
- 很多異步方法的調用鏈實際上隻有最裏層的異步方法才會真正暫停,
再有,等待異步操作完成後繼續執行:
class StateMachine{ private int state = 0; // 創建一個用來存儲結果的 Task<int> ,async/await 模型下,這使得 Green Thread 與這類硬件控製流保護機製的集成變得更加複雜,因此在涉及係統調用時 ,既然 C# 編譯器無法判斷 , add ebx, r12d mov eax, ebx ; return value xor ecx, ecx ; null Continuation retSUSPEND_FIRST: ; Fib(n - 1) 暫停了 ,但實際上大部分負載都是同步的 。那麽直接返回一個Task<int>對象包裝一下結果即可。因此運行時需要在兩種調用約定之間放置一個邊界 ,例如在一個異步方法裏調用了一個同步方法 ,同時額外增加一條用於傳遞 Continuation 的通道 。合著 Green Thread 需要妥協這麽多東西最後還不如原來的 async/await 性能好 。如果
rcx == null

