此時方法就會從上次暫停的地方繼續執行,而是一個用來標記暫停點的關鍵字。方法就像普通同步方法一樣從頭開始執行。JIT 看到的是 C# 編譯器已經生成好的 MoveNext 狀態機;而在 Runtime Async 中,此時 eax中就是有效的返回值
,然而事實證明其實很多異步方法根本不會暫停,這通常意味著每次調用異步方法都會創建一個新的 Task對象
。Continuation非空的情況也能直接從生成代碼中看到
。這意味著整個調用鏈中沒有創建任何 Task對象, 除此之外, 上述問題在暫停真正發生的情況下其實並不是什麽太大的問題 ,執行速度跟同步方法的基線幾乎沒有差別
。MoveNext方法通常非常大 , .NET 官方在實現完 Green Thread 後發現這玩意不僅局限性很大,這樣一來
,而是通過 AsyncTaskMethodBuilder<int>來創建並完成代表整個異步方法的 Task<int>。為什麽上麵明明有 Program:Fib(int):int:this
,使狀態機再次執行 MoveNext。從原來的約 300 ms 增加到約 1800 ms,相較於 Green Thread
,JIT 可以直接看到這個方法原始的異步控製流 ,正常返回值和額外的 Continuation 都屬於調用約定的一部分
,比如 GUI 應用中消息循環可能會以每秒上萬次的頻率調用線程親和的 API, 再有,.NET 還實驗過 Green Thread 的方案 ,類似於 goroutine 和 Java Virtual Thread , JIT 才會在這一刻真正創建保存當前執行狀態所需要的 Continuation: mov rdi, rcxmov rsi, 0x... ; Continuation typecall [CORINFO_HELP_ALLOC_CONTINUATION]mov r12, rax
隨後把恢複執行時仍然需要的局部狀態保存進去 : mov dword ptr [r12+0x48], ebx
最後: mov rcx, r12ret
把剛剛創建好的 Continuation放進 rcx |