Introduction
1. 本章主要内容
第 2 章是 perfbook 的引言,从宏观层面介绍了并行编程的背景、目标、替代方案和核心困难。本章内容偏概念性,为后续章节奠定基础。
1.1 历史上并行编程困难的原因 (sec:intro:Historic Parallel Programming Difficulties)
作者指出,并行编程之所以被认为困难,很大程度上是历史原因造成的,而非技术本身不可逾越:
- 并行系统成本高、稀有:过去并行硬件价格昂贵,只有少数人能接触
- 缺乏经验:研究者与实践者很少有机会使用并行系统
- 缺乏公开代码:20 世纪的大型并行软件几乎都是专有闭源的
- 缺乏工程学科:没有形成被广泛理解的并行编程工程方法论
- 通信开销高:即使在紧密耦合的共享内存系统中,通信开销也远高于处理开销
作者强调,前四个困难已经基本被克服(多核普及、开源项目如 Linux 内核、经验丰富的开发者社区),但第五个困难(通信开销)由于光速和物质原子性的物理限制,依然存在。
1.2 并行编程的三大目标:铁三角 (sec:intro:Parallel Programming Goals)
并行编程在顺序编程目标之上,额外面临三个相互制约的目标:
| 目标 | 含义 | 优先级场景 |
|---|---|---|
| Performance (性能) | 包括吞吐、可扩展性 (per CPU)、能效 (per watt) | 底层基础设施、内核、数据库 |
| Productivity (生产力) | 开发效率、维护成本 | 上层应用、业务逻辑 |
| Generality (通用性) | 跨平台、跨场景复用能力 | 中间件、库、框架 |
核心观点:在当前技术条件下,任何并行程序最多只能同时满足其中两个目标,这被称为 “铁三角” (Iron Triangle)。
- C/C++ + Locking + Threads:性能好、通用性强,但生产力低
- SQL:生产力极高、性能不错,但通用性弱(仅限关系型查询)
- MPI:性能/可扩展性极强,但生产力低
- OpenMP:生产力较高,但特定于循环并行化,通用性受限
1.3 并行编程的替代方案 (sec:intro:Alternatives to Parallel Programming)
在追求性能时,并行化并非唯一选择:
- 运行多个顺序应用实例 (Embarrassingly Parallel)
- 用 shell 脚本同时启动多个独立进程
- 优点:零开发成本,极大性能提升
- 缺点:内存冗余、重复计算、数据拷贝
- 使用现有并行软件
- 关系数据库(自动并行化查询)
- Web 应用服务器、Map-Reduce 环境
- 并行数值计算库(利用 GPU/向量单元)
- 优化顺序应用
- 用 hash table 替换链表可获得数量级提升
- 消除 I/O 瓶颈、内存瓶颈、缓存瓶颈
- 并行化只是众多性能优化手段之一
1.4 什么让并行编程困难? (sec:intro:What Makes Parallel Programming Hard?)
作者将并行编程特有的困难归纳为四大类任务:
1.4.1 工作划分 (Work Partitioning)
- 必须有可划分的工作,否则就是顺序执行
- 不均匀划分会导致负载失衡(Amdahl 定律)
- 划分增加全局错误处理的复杂度
- 线程数量需要控制:过多导致缓存溢出,过少无法重叠计算与 I/O
1.4.2 并行访问控制 (Parallel Access Control)
- 访问形式:本地变量直接访问 vs 远程变量需要消息传递
- 协调机制:消息传递、锁、事务、引用计数、显式时序、原子变量、数据所有权
- 死锁、活锁、事务回滚都源于协调问题
1.4.3 资源划分与复制 (Resource Partitioning and Replication)
- 最有效的并行策略:划分写密集型资源,复制读多写少资源
- 划分粒度:系统、存储设备、NUMA 节点、CPU 核心、页、缓存行、锁实例、临界区
- 粗划分优于细划分:减少同步开销占比(见代码示例
resource_partition.c)
1.4.4 与硬件交互 (Interacting With Hardware)
- 通常由 OS/编译器/库处理
- 但在追求极致性能或直接操作新硬件时需要手动处理
- 需考虑缓存几何、系统拓扑、互联协议
1.4.5 复合能力与顺序设计的限制
- 数据并行是工作划分 + 访问控制 + 资源划分的复合
- 现有的顺序 API 设计可能成为并行化的障碍(如 hash table 返回精确计数)
2. 核心观点总结
-
并行编程的”难”主要是感知上的难:源于历史上硬件昂贵稀有。如今多核普及,这种感知正在改变。
-
并行编程是性能优化的一种:如果程序已经够快,不要并行化。要比较并行算法与最优顺序算法。
-
铁三角不可兼得:性能、生产力、通用性三者必须取舍。底层追求性能和通用性,上层追求生产力。
-
划分和复制是核心策略:将写操作分散到不同资源上,将读多数据复制到本地,是获得可扩展性的关键。
-
不要忽视顺序优化:在很多情况下,优化数据结构(如链表改哈希表)比并行化收益更大。
-
通信是永恒瓶颈:光速和物质原子性限制了通信速度,工程学科已经演化出实用的应对策略。
本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。