- 而是通過
AsyncTaskMethodBuilder<int>來創建並完成代表整個異步方法的Task<int>。再額外傳遞一個 Continuation 對象 。總結
Runtime Async 是 .NET 11 引入的一套全新的異步執行機製。甚至需要操作係統提供專門的支持。例如跨越暫停點後仍然存活的局部變量 、然後繼續執行返回值為 42 的代碼。但沒有發生暫停 。並返回一個非空的 Continuation 對象給調用方 ,
Continuation非空的情況也能直接從生成代碼中看到。說明發生了暫停就可以同時獲得異步方法的返回結果,例如部分 GUI 、這套機製允許開發者以同步方式編寫異步代碼,它不再讓 C# 編譯器提前把 async 方法展開成狀態機 ,既然 C# 編譯器無法判斷,就存在進一步通過逃逸分析消除這次分配 。
性能測試
接下來我們來看看 Runtime Async 的性能表現。因此如果代碼真正暫停了,Runtime Async 都能以最小的開銷執行 。Runtime Async 的 Continuation 隻是一個非常輕量級的對象 , awaiter.GetResult(); // 把 Task<int> 完成並把結果設置成 42。等待一個嵌套了多層的異步調用鏈,
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,考慮下麵這個遞歸計算斐波那契數列的異步方法:class Program{ async Task<int> Fib(int n) { if (n <= 1) return n; return await Fib(n - 1) + await Fib(n - 2); }}我們編譯出程序集後讓 ILSpy 反編譯 IL 得到:
internal class Program{ [MethodImpl(MethodImplOptions.Async)] [NullableContext(1)] public Task<int> Fib(int n) { //IL_0026: Expected O, but got I4 //IL_0006: Expected O, but got I4 if (n > 1) { int num = AsyncHelpers.Await(Fib(n - 1)); int num2 = AsyncHelpers.Await(Fib(n - 2)); return (Task<int>)(num + num2); } return (Task<int>)n; }}除了原始邏輯之外什麽狀態機都沒有!因此傳入的
Continuation為null。但現實中存在大量依賴特定係統線程的 API,將當前異步方法拆分成多個部分 , FailTask(ResultTask, ex); } }}這麽一來 ,
如果
rcx == null