1. 为什么需要并行算法?
现代CPU早已进入多核时代,即使是入门级处理器也普遍拥有4-8个物理核心。但传统串行代码只能利用单个核心的计算能力,导致大量计算资源闲置。我曾用性能分析器观察过一个图像处理程序,发现CPU利用率长期低于15%,这简直是对硬件资源的巨大浪费。
C++17引入的并行算法库正是为了解决这个问题。通过std::execution策略,开发者可以用极小的代码改动,将现有算法并行化。在我的一个矩阵乘法实验中,简单添加par_unseq策略后,8核CPU上的性能提升了近6倍。
2. 并行执行策略详解
2.1 三种标准执行策略
C++17定义了三种标准执行策略:
- seq:顺序执行(默认)
- par:并行执行
- par_unseq:并行+向量化执行
实际测试表明,不同策略对性能影响显著。我在i7-11800H处理器上测试了1000万次浮点运算:
| 策略 | 执行时间(ms) | CPU利用率 |
|---|---|---|
| seq | 152 | 12% |
| par | 28 | 92% |
| par_unseq | 19 | 98% |
2.2 策略选择实践建议
根据我的项目经验,策略选择需要考虑:
- 数据依赖性:存在数据竞争时只能用seq
- 内存访问模式:par_unseq需要连续内存布局
- 算法特性:排序类算法更适合par
注意:并行算法不是银弹。对于小数据集(<1K元素),线程创建开销可能抵消并行收益。
3. 实战:图像处理并行化改造
3.1 原始串行实现
典型的图像锐化算法串行实现:
cpp复制void sharpen_image(const Image& src, Image& dst) {
for (int y = 1; y < src.height-1; ++y) {
for (int x = 1; x < src.width-1; ++x) {
// 3x3卷积核计算
float sum = 0.0f;
for (int ky
