[C#] 平行處理到底用哪個?Task.WhenAll , Parallel.ForEach 最簡單選法筆記
最近在看一些 open source 的 專案,看到一個關鍵字 Task.WhenAll ,看了一下跟 Parallel.ForEach
看起來不是差不多的東西嗎? 問一下 GPT 原來是有差異的,今天筆記一下,希望自己以後可以用的比較恰當..
先一句話簡單兩個區別:
Task.WhenAll = 非同步 I/O Turbo 模式
Parallel.ForEach = CPU 多核心 Turbo 模式
所以簡單的說,如果大量平行呼叫服務操作建議使用 Task.WhenAll , 這點是我很常犯的,畢竟我常常就是無腦 Parallel.ForEach
直接做平行處理
這舉幾個常用案例 -
1. 大量 I/O ,這邊裡有一個迷思,如果我是大量讀取檔案做反序列化,算是大量 File I/O 處理嗎?
雖然是大量 File I/O 讀取,但是因為你會處理檔案譬如反序列化,或是讀取出來做一些位元推移,所以建議還是使用 Parallel.ForEach
畢竟這還是處於大量CPU 處理範圍,但是如果是呼叫呼叫外部 API則使用 Task.WhenAll
2. 大量 CPU ,比較常見就是讀取大量檔案(而且要處理檔案)或是資料庫資料處理。
3. 無法判斷怎麼辦?! 其實我個人都會先用 Parallel.ForEach ,但是只要想到這 Task 可能不需要使用到大量 CPU,只是數量多而已
就可以使用 Task.WhenAll ,GPT 是推薦,兩個可以分批使用先透過 Task.WhenAll 拉回資料後,使用 Parallel.ForEach
這邊給上 GPT 給我的 快速查表
-
| 功能 | Task.WhenAll | Parallel.ForEach |
|---|---|---|
| 適用場景 | I/O(等待遠端) | CPU heavy(做計算) |
| ThreadPool 使用 | 幾乎不佔用 | 佔滿 CPU 核心 |
| 效能 | 同時等待 → 快 | 同時計算 → 快 |
| 不適合 | CPU heavy | I/O |
| 呼叫 async | 可以 | 不行(會 deadlock 或變慢) |
這邊也附上一些狀況推薦使用的情形 GPT 提供的推演狀況
| 你的 JSON 檔案來源 | 用什麼? | 原因 |
|---|---|---|
| SSD / NVMe 本地小檔大量讀取 | Parallel.ForEach | Deserialize 超吃 CPU |
| 本機 HDD 大量小檔 | Parallel.ForEach | 仍然 CPU bottleneck |
| Network Share / NAS(慢) | Task.WhenAll | I/O latency 很高 |
| AWS S3 / GCS 下載 | Task.WhenAll | 典型 I/O Bound |
| 單檔很大(>100MB) | Task.WhenAll | I/O Reading 才是瓶頸 |
| 讀完 JSON 後還要大量 CPU 處理 | Parallel.ForEach | 全程 CPU 為主 |
先筆記到這邊,總結一下,Task.WhenAll 和 Parallel.ForEach 根本不是替代品
Task.WhenAll 適合等東西:I/O bound、外部 API、資料庫、檔案讀寫
Parallel.ForEach 適合算東西:CPU bound、影像處理、反序列化、資料批次運算
總之等的用 Task.WhenAll,算的用 Parallel.ForEach,當然這都是你最後再優化上面再拉升效能的手段之一
