在當今多核處理器普及的時代,高效利用計算資源成為開發者必備技能。本文將深入剖析C#中的并行編程利器——任務并行庫(TPL)和經典異步模式,助你提升程序性能。
🚀 一、任務并行庫(TPL)核心機制
1. Parallel.For:并行化的for循環
通過簡單改造傳統for循環實現多核并行計算:
Parallel.For(0, 15, i => Console.WriteLine($"The square of {i} is {i*i}"));
- 執行特點:迭代獨立且無序執行,自動分配線程資源
- 關鍵參數:
fromInclusive
:起始索引(包含)toExclusive
:結束索引(不包含)Action<int>
:迭代邏輯委托
實用場景:矩陣運算、批量圖像處理等CPU密集型任務
2. Parallel.ForEach:集合并行處理器
高效處理IEnumerable集合的并行方案:
string[] words = {"We", "hold", "these", "truths"};
Parallel.ForEach(words, word => Console.WriteLine($"\"{word}\" has {word.Length} letters"));
- 智能分配:自動分割集合元素到不同線程
- 注意事項:集合需線程安全,避免共享狀態修改
實戰技巧:數據批處理時優先選擇ForEach,代碼更簡潔
🔄 二、并行循環的三大特性
1. 自動負載均衡
TPL動態監控CPU負載,智能分配迭代任務到不同核心
2. 結果順序保留
即使執行順序隨機,結果數組仍保持原始順序:
int[] squares = new int[50];
Parallel.For(0, 50, i => squares[i] = i * i);
// 結果:[0,1,4,9...2401] 保持索引順序
3. 異常聚合機制
自動捕獲所有線程異常,拋出AggregateException
統一處理
? 三、經典異步編程模式解析
雖然async/await已成主流,但理解傳統模式仍具價值:
委托異步三劍客:
delegate int MyDel(int x);
MyDel del = x => x * x;// 1. 開始異步執行
IAsyncResult iar = del.BeginInvoke(5, null, null);// 2. 獲取結果
int result = del.EndInvoke(iar);
三種經典模式對比:
模式 | 實現方式 | 適用場景 |
---|---|---|
等待直到完成 | EndInvoke 阻塞調用 | 簡單異步,需立即結果 |
輪詢模式 | 循環檢查IsCompleted 屬性 | 需中間處理的長時間任務 |
回調模式 | AsyncCallback 委托通知 | 事件驅動架構,避免主線程阻塞 |
回調模式示例:
del.BeginInvoke(5, ar => {int res = del.EndInvoke(ar);Console.WriteLine($"Result: {res}");
}, null);
?? 四、新舊異步模式對比
傳統模式痛點:
- 代碼嵌套復雜(回調地獄)
- 手動線程管理易出錯
- 異常處理困難
async/await革命性優勢:
async Task<int> CalculateAsync()
{return await Task.Run(() => 5 * 5);
}
- 線性代碼結構
- 自動上下文延續
- 同步的異常處理機制
💡 五、實戰建議
1. 并行選擇策略:
- CPU密集型:優先選用
Parallel.For/ForEach
- IO密集型:選擇
async/await
+Task.Run
2. 避坑指南:
// 錯誤示例:共享變量未保護
int sum = 0;
Parallel.For(0, 100, i => sum++); // 結果不確定 // 正確方案:使用線程安全操作
Interlocked.Add(ref sum, 1);
3. 性能優化:
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount - 1
};
Parallel.For(0, 1000, options, ...);
🌟 結語
掌握并行編程如同獲得性能加速器:
- 多核計算首選TPL并行循環
- 現代項目優先采用async/await
- 理解傳統模式有助于解決遺留系統問題
性能測試挑戰:嘗試對比Parallel.For與普通for循環在1000萬次計算中的性能差異,評論區分享你的測試結果!👇