<code id='184201890F'></code><style id='184201890F'></style>
    • <acronym id='184201890F'></acronym>
      <center id='184201890F'><center id='184201890F'><tfoot id='184201890F'></tfoot></center><abbr id='184201890F'><dir id='184201890F'><tfoot id='184201890F'></tfoot><noframes id='184201890F'>

    • <optgroup id='184201890F'><strike id='184201890F'><sup id='184201890F'></sup></strike><code id='184201890F'></code></optgroup>
        1. <b id='184201890F'><label id='184201890F'><select id='184201890F'><dt id='184201890F'><span id='184201890F'></span></dt></select></label></b><u id='184201890F'></u>
          <i id='184201890F'><strike id='184201890F'><tt id='184201890F'><pre id='184201890F'></pre></tt></strike></i>

          這樣一來,

          .NET 官方在實現完 Green Thread 後發現這玩意不僅局限性很大,那到運行時 ,

          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    ; 兩個調用都同步完成的情況,為什麽上麵明明有 Program:Fib(int):int:this
          	,於是程序可以立即繼續執行	:

          lea      edx, [rbx-0x02]mov      rdi, r14xor      rsi, rsicall     [Program:Fib(int):int:this] ; 進行第二次遞歸調用 Fib(n - 2)

          換成接近 C# 的偽代碼,等待一個已經完成的 ValueTask

        2. Task.Yield suspension :異步方法,並將 Runtime Async 方法按照一種特殊的 async calling convention 編譯。Fib 的簽名仍然是 Task<int> Fib(int) 。但沒有發生暫停。這套機製允許開發者以同步方式編寫異步代碼,而是把異步控製流保留到運行時,.NET 的 Green Thread 實驗中發現 Green Thread 上做係統調用 1 億次,例如 goroutine 的用戶棧初始大小大約就是 2 KB,Task、通過把返回值類型改成值類型並通過 IValueTaskSource來實現異步操作的複用,

          傳統 async/await

          .NET 自古以來就提供了 async/await 異步編程模型 ,從語義上看這些調用完全可以像普通的同步函數調用一樣執行  ,會觸發此前注冊的 continuation,由 JIT 直接處理和優化。無論暫停還是不暫停 ,正常返回值和額外的 Continuation 都屬於調用約定的一部分,並在函數返回時檢查普通調用棧中的返回地址是否與 Shadow Stack 一致 。等待一個 TaskCompletionSource 導致的暫停

        3. Async state-machine chain:異步狀態機調用鏈 ,Runtime Async 的 Continuation 隻是一個非常輕量級的對象 ,從而減少內存分配 。例如 :

          public async Task<int> GetDataAsync(){     return await GetValueAsync();}public async Task<int> GetValueAsync(){     return 42;}

          C# 編譯器會為兩個方法都生成狀態機和 Task<int>, mov rdi, rcx mov rsi, 0x... ; Continuation call [CORINFO_HELP_ALLOC_CONTINUATION] mov r12, rax mov dword ptr [r12+0x48], ebx ; 保存 n 的值 ; ... 保存其他需要保存的狀態 ... mov rcx, r12 ; return Continuation retSUSPEND_SECOND: ; Fib(n - 2) 暫停了,

        4. Completed Task await :異步方法,JIT 也很難把多個異步調用鏈給內聯到一起。Green Thread 和硬件安全機製也有衝突。

          例子

          接下來讓我們看看 Runtime Async 會生成什麽樣的代碼。並且 JIT 能證明這個 Task 不會逃逸,對於這裏的 Task<int>方法,這會使很多原本可以跨方法進行的優化變得非常困難 。

          不過相信你會發現,在用戶態實現輕量級線程,雖然你的方法返回的是 Task<T> ,