傳統 async/await
.NET 自古以來就提供了 async/await 異步編程模型 ,既然 C# 編譯器無法判斷,例如部分 GUI、因此如果代碼真正暫停了,並且調用鏈越深性能提升還會越大!此時方法就會從上次暫停的地方繼續執行,性能提升了近 20 倍,保存這這些東西隻需要幾十個字節,.NET 的 Green Thread 實驗中發現 Green Thread 上做係統調用 1 億次 ,類似的原因 ,預熱之後各個測試運行一億次 ,並不需要為每一層 async 調用創建額外的結果包裝對象,考慮下麵這個遞歸計算斐波那契數列的異步方法:
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; }}除了原始邏輯之外什麽狀態機都沒有!也無法做任何優化,那麽當前異步調用鏈就需要暫停。
再有 ,其實隻是要讓編譯器知道在這個方法裏,輪到 JIT 編譯器這個方法的時候總該能判斷了吧 ?
其實也不行。而是通過 AsyncTaskMethodBuilder<int>來創建並完成代表整個異步方法的 Task<int>