并行计算基础:任务分解、加速比与可扩展性 / Parallel Computing Fundamentals: Decomposition, Speedup, and Scalability
📅 创建时间:2026-07-20 🏷️ 标签:#并行计算 #Amdahl定律 #Gustafson定律 #性能模型 📚 前置知识:[[00-parallel-computing-overview]] 📚 相关知识:[[/02-systems-and-performance/02-computer-architecture-and-hardware/02-parallel-computing-theory]]
1. 并行之前先判断“能否拆分”
假设程序由以下步骤组成:
读取数据 → 预处理 → 核心计算 → 汇总结果 → 写入文件只有相互独立的部分能够同时执行。任务之间常见依赖包括:
- 数据依赖:后一步需要前一步的结果
- 控制依赖:是否执行由前一步判断决定
- 资源依赖:多个任务竞争同一文件、锁或设备
数据并行与任务并行
数据并行:同一种操作处理不同数据
例:多个线程分别处理图像的不同行
任务并行:不同任务同时处理同一流程的不同阶段
例:一个线程读取、一个线程解码、一个线程推理GPU 主要擅长数据并行,CPU 更容易同时承载数据并行和任务并行。
2. 衡量并行性能
加速比
S(p) = T(1) / T(p)如果单线程需要 100 秒,8 线程需要 20 秒,则加速比为 5,而不是 8。
并行效率
E(p) = S(p) / p上例的并行效率是 5 / 8 = 62.5%。剩余能力消耗在串行部分、同步、调度和负载不均上。
吞吐与延迟
- 延迟:完成单个任务需要多久
- 吞吐:单位时间能完成多少任务
GPU 往往提高吞吐,但单个小任务不一定比 CPU 延迟更低。
3. Amdahl 定律:固定问题规模的上限
如果程序中可并行比例为 P,使用 N 个处理器:
S(N) = 1 / ((1 - P) + P / N)当 95% 可以并行时,即使处理器无限多:
最大加速比 = 1 / (1 - 0.95) = 20这说明优化串行路径可能比继续增加核心更重要。
| 可并行比例 | 理论最大加速比 |
|---|---|
| 50% | 2 倍 |
| 90% | 10 倍 |
| 95% | 20 倍 |
| 99% | 100 倍 |
4. Gustafson 定律:问题规模也会增长
现实中获得更多计算资源后,通常不是只想更快完成原问题,而是希望处理更大的网格、更高分辨率或更大的模型。
S(N) = N - α(N - 1)其中 α 是串行部分比例。Gustafson 定律解释了为什么超级计算机仍然有价值:资源增加后,可以扩大并行工作规模。
5. 强扩展与弱扩展
强扩展
保持总问题规模不变,增加处理器数量。
固定 1 亿个网格单元:1 核 → 8 核 → 64 核处理器越多,每个处理器分到的工作越少,通信占比最终会上升。
弱扩展
每个处理器的工作量保持不变,处理器增加时同步扩大问题规模。
每核处理 100 万个网格单元:1 核 100 万 → 64 核 6400 万弱扩展更能反映大型科学计算系统的容量能力。
6. 粒度、调度与负载均衡
并行粒度
- 粗粒度:任务大、调度少,但可能不均衡
- 细粒度:任务均衡机会多,但调度和同步成本高
任务耗时只有几百纳秒时,放进线程池可能比直接执行更慢。
静态调度与动态调度
- 静态调度:提前分工,开销低,适合任务耗时相近
- 动态调度:运行时领取任务,均衡好,但有额外竞争
负载不均衡
线程 A:100 ms
线程 B:102 ms
线程 C:98 ms
线程 D:300 ms ← 所有人都要等它并行阶段耗时由最慢参与者决定。
7. 同步不是免费的
互斥锁、原子操作、Barrier 和消息通信都会带来等待。常见优化方向:
- 减少共享可变状态
- 批量处理,降低同步频率
- 使用线程局部数据,最后统一归并
- 让通信与计算重叠
- 通过无锁结构降低阻塞,但不要默认无锁一定更快
历史并行基础补充
本页保留合并前的并行理论入门。
当前版本增加 DAG、Work/Span、正确性和实验方法。
DAG
任务是节点,依赖是边。
Ready Task 的前置依赖已经完成。
Work
Work 是全部任务成本。
减少 Work 通常是算法优化。
Span
Span 是最长依赖路径。
更多资源不能短于 Span。
并行度
parallelism = Work / Span它给出可利用并行度的粗略上限。
真实依赖
由算法读写关系决定。
不能通过忽略同步消除。
伪依赖
由共享容器、全局锁和实现顺序造成。
分片和线程局部状态可以减少。
粒度
细任务调度多。
粗任务并行度低且尾部大。
静态调度
规则任务使用固定分块。
行为可预测,开销小。
动态调度
不规则任务使用队列。
Chunk 在开销和均衡之间选择。
Work Stealing
空闲 Worker 从其他队列窃取。
改善不均,增加调度与局部性成本。
串行区
初始化、I/O、提交、锁和归约可能串行。
通信
通信含延迟、字节、协议、拥塞和同步。
同步范围
线程、Block、进程和节点具有不同范围。
范围越大,协调成本通常越高。
数据竞争
共享写缺少同步导致错误。
死锁
循环等待造成无进展。
统一顺序和结构化协议降低风险。
活锁
线程持续重试但没有完成工作。
饥饿
任务长期无法获得资源。
调度公平性需要设计。
浮点
并行归约改变舍入顺序。
使用容差或确定性树。
Amdahl
固定规模的串行比例限制加速。
Gustafson
资源增加时可以扩大问题规模。
强扩展
固定总工作,观察效率。
弱扩展
固定每资源工作,观察全局成本。
基线
串行版本必须正确且合理。
Profile
分解计算、移动、同步、等待、I/O 和不均衡。
正确性
- 结果;
- 容差;
- 数据竞争;
- 内存安全;
- 取消;
- 资源释放。
实验记录
- 输入;
- 算法;
- 硬件;
- 编译器;
- 资源数;
- 调度;
- 样本;
- 原始数据;
- 正确性。
历史边界
旧线程和节点结论不能直接外推。
当前平台重新建立基线。
当前课程映射
当前版本增加:
- DAG;
- Work/Span;
- 调度;
- 正确性;
- 强弱扩展;
- Profile;
- 完成标准。
章节测试
- 为什么 16 核程序通常无法获得 16 倍加速?
- 图像逐像素处理更接近数据并行还是任务并行?
- 固定网格规模增加节点属于强扩展还是弱扩展?
- 为什么任务拆得过细也会降低性能?
参考答案
- 存在串行部分、同步、调度、访存和负载不均。
- 数据并行。
- 强扩展。
- 调度、通信和同步成本可能超过任务本身。
下一篇:[[02-processor-architecture]]