在当今多核处理器普及的时代,高效利用计算资源成为开发者必备技能。本文将深入剖析C#中的并行编程利器------任务并行库(TPL)和经典异步模式,助你提升程序性能。
🚀 一、任务并行库(TPL)核心机制
1. Parallel.For:并行化的for循环
通过简单改造传统for循环实现多核并行计算:
csharp
Parallel.For(0, 15, i =>
Console.WriteLine($"The square of {i} is {i*i}"));
- 执行特点:迭代独立且无序执行,自动分配线程资源
- 关键参数:
fromInclusive
:起始索引(包含)toExclusive
:结束索引(不包含)Action<int>
:迭代逻辑委托
实用场景:矩阵运算、批量图像处理等CPU密集型任务
2. Parallel.ForEach:集合并行处理器
高效处理IEnumerable集合的并行方案:
csharp
string[] words = {"We", "hold", "these", "truths"};
Parallel.ForEach(words, word =>
Console.WriteLine($"\"{word}\" has {word.Length} letters"));
- 智能分配:自动分割集合元素到不同线程
- 注意事项:集合需线程安全,避免共享状态修改
实战技巧:数据批处理时优先选择ForEach,代码更简洁
🔄 二、并行循环的三大特性
1. 自动负载均衡
TPL动态监控CPU负载,智能分配迭代任务到不同核心
2. 结果顺序保留
即使执行顺序随机,结果数组仍保持原始顺序:
csharp
int[] squares = new int[50];
Parallel.For(0, 50, i => squares[i] = i * i);
// 结果:[0,1,4,9...2401] 保持索引顺序
3. 异常聚合机制
自动捕获所有线程异常,抛出AggregateException
统一处理
⏳ 三、经典异步编程模式解析
虽然async/await已成主流,但理解传统模式仍具价值:
委托异步三剑客:
csharp
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 委托通知 |
事件驱动架构,避免主线程阻塞 |
回调模式示例:
csharp
del.BeginInvoke(5, ar => {
int res = del.EndInvoke(ar);
Console.WriteLine($"Result: {res}");
}, null);
⚖️ 四、新旧异步模式对比
传统模式痛点:
- 代码嵌套复杂(回调地狱)
- 手动线程管理易出错
- 异常处理困难
async/await革命性优势:
csharp
async Task<int> CalculateAsync()
{
return await Task.Run(() => 5 * 5);
}
- 线性代码结构
- 自动上下文延续
- 同步的异常处理机制
💡 五、实战建议
1. 并行选择策略:
- CPU密集型:优先选用
Parallel.For/ForEach
- IO密集型:选择
async/await
+Task.Run
2. 避坑指南:
csharp
// 错误示例:共享变量未保护
int sum = 0;
Parallel.For(0, 100, i => sum++); // 结果不确定
// 正确方案:使用线程安全操作
Interlocked.Add(ref sum, 1);
3. 性能优化:
csharp
var options = new ParallelOptions {
MaxDegreeOfParallelism = Environment.ProcessorCount - 1
};
Parallel.For(0, 1000, options, ...);
🌟 结语
掌握并行编程如同获得性能加速器:
- 多核计算首选TPL并行循环
- 现代项目优先采用async/await
- 理解传统模式有助于解决遗留系统问题
性能测试挑战:尝试对比Parallel.For与普通for循环在1000万次计算中的性能差异,评论区分享你的测试结果!👇
