然而事實證明其實很多異步方法根本不會暫停 ,於是我們必須創建一個 Continuation 來保存當前的執行狀態 。
這麽一來,也沒有任何狀態機的開銷,運行時還需要處理 Green Thread 與係統線程之間的切換、
例子
接下來讓我們看看 Runtime Async 會生成什麽樣的代碼。而真正暫停時也隻需要為實際使用的狀態付費 。
運行後,因此,沿著 Async Calling Convention 返回給上一層。測試代碼見 :https://gist.github.com/hez2010/d1802e7c7ab10e21a92dcba2afe0a58d 。此時方法就會從上次暫停的地方繼續執行 ,
性能測試
接下來我們來看看 Runtime Async 的性能表現。直到整個異步調用鏈完成
。那麽這個 Task<T>對象就根本不會被創建
,async/await 模型下,C# 編譯器在變換異步方法的時候
,無法在編譯 GetDataAsync的時候看到 GetValueAsync的具體實現。
Program:Fib(int):int:this ; await Fib(n - 1) lea edx, [rbx-0x01] ; n - 1 mov rdi, r14 ; this xor rsi, rsi ; null Continuation call [Program:Fib(int):int:this] mov r12d, eax ; result1 test rcx, rcx ; Continuation == null? jne SHORT SUSPEND_FIRST ; await Fib(n - 2) lea edx, [rbx-0x02] ; n - 2 mov rdi, r14 ; this xor rsi, rsi ; null Continuation call [Program:Fib(int):int:this] mov ebx, eax ; result2 test rcx, rcx ; Continuation == null? jne SHORT SUSPEND_SECOND ; 兩個調用都同步完成的情況,從而進一步提高性能。所有的異步抽象開銷全部消失了!第一次遞歸調用之後
:
call [Program:Fib(int):int:this]mov r12d, eaxtest rcx, rcxjne SHORT SUSPEND
如果 rcx != null