async/await 的價值

async/await 的價值不是讓程式更快,而是「讓等待 I/O 的時間不佔用 thread,提升整體系統吞吐量」。

以前只知道寫async/await ,但不知道為什麼要寫,聽說效能會變快!?   這樣觀念不對

async/await 核心本質  = 暫停方法 + 註冊 continuation +(必要時)釋放 thread
 

Console.WriteLine($"Before A Start Thread: {Thread.CurrentThread.ManagedThreadId}");

await A();

Console.WriteLine($"After A End Thread: {Thread.CurrentThread.ManagedThreadId}");

async Task A()
{
  	Console.WriteLine($"A before delay Thread: {Thread.CurrentThread.ManagedThreadId}");
  
	await Task.Delay(2000); // Thread 被釋放回 Thread Pool
  
	Console.WriteLine($"A after delay Thread: {Thread.CurrentThread.ManagedThreadId}");
}
執行結果:
Before A Start Thread: 1
A before delay Thread: 1
A after delay Thread: 11
After A End Thread: 11

根據上面顯示,進入A()時,不會釋放Thread,再去Thread Pool拿Thread,而是await  A()進入方法後,由該方法內部的 await 決定是否釋放 thread。
await 的作用是:讓方法在非同步操作未完成時,暫停執行,並在完成後繼續執行;是否釋放 thread 取決於等待的操作是否為真正的非同步 I/O。

如何分辨I/O-bound或CPU-bound :

類型是否適合 async/await是否需要 Task.Run判斷重點
I/O-bound(HttpClient / EF Core / File / DB / Redis)✔ 適合❌ 不需要在「等外部系統」
CPU-bound(迴圈 / 圖片處理 / 壓縮 / 加密 / 排序)❌ 不適合純 async✔ 需要(或 Parallel)在「本機 CPU 計算」

I/O -bound 指的是:
「等待外部系統(網路、資料庫、檔案、時間)完成的操作」,這種等待不應該佔用 thread,因此才需要 async/await。

CPU-bound 指的是:
程式的主要時間花在「CPU 計算」,而不是等待外部資源,意旨程式一直在「算東西」。

用 Task.Run 或 Parallel(讓 CPU 分工處理),目的不是加速,而是把 CPU 工作移到 Thread Pool,避免阻塞目前執行緒(避免佔用 request/UI thread),提高整體系統吞吐量。

// 純運算式,如大量運算用Task.Run
public async Task<int> CalculateAsync()
{
   return await Task.Run(() =>
   {
       int sum = 0;
       for (int i = 0; i < 1_000_000; i++)
           sum += i;
       return sum;
   });
}

延伸閱讀:

await ConfigureAwait(false) = 不要回到原本的 context(UI / request context)

項目預設 awaitConfigureAwait(false)
是否回原 thread✔ 會❌ 不會
是否捕捉 context✔ 會❌ 不會
適用場景UI / 需要 thread 安全library / backend
項目ASP.NET FrameworkASP.NET Core
SynchronizationContext✔ 有❌ 沒有
await 後是否回原 thread✔ 會❌ 不會(本來就沒有)
ConfigureAwait(false)很重要幾乎沒差

ASP.NET Core 不需要 SynchronizationContext,因此 await continuation 預設就會在線程池執行,ConfigureAwait(false) 幾乎沒有行為差異。