并行编程存在的问题
- 死锁
- 活锁
- 竞争条件
- 不确定性
- 扩展性限制
- 实时延迟
并行编程的目标
-
性能
- 性能方面的关注焦点已经从硬件转向并行软件
-
生产率
- 高效的利用开发者已经变得更为重要
-
通用性
- 分摊成本
- 带来更大的性能损失或者生产率损失
- c/c++
- 锁及线程
- POSIX线程
- pthreads
- Windows线程
- 性能优秀
- 良好的通用性
- 生产率较低
- java
- 性能稍低
- 生产率高
- MPI
- 通用科学计算
- 优秀的性能和可扩展性
- 生产率低于c/c++
- OpenMP
- 用于特定任务
- 比MPI和c/c++更简单
- SQL
- 性能优秀
- TPC测试性能出色
- 生产率优秀
- c/c++
CPU MIPS MIPS(Million Instructions Per Second): 单字长定点指令平均执行速度 Million Instructions Per Second的缩写,每秒处理的百万级的机器语言指令数
-
分层:
- 应用层
- 中间件层
- 系统库
- 操作系统内核
- 固件(驱动)
- 硬件
-
越往上层,生产率越重要
-
越往下层,性能和通用性越重要
-
底层开发的大量工作成本,必须被大量的上层用户所分摊
-
下层的性能损失,在上层是难以恢复的
-
越往上层,直接采购额外的硬件通常比额外的开发者更划算
并行编程的替代方案
- 运行多个串行应用实例
- 增加了内存消耗
- CPU指令周期浪费(重复中间结果)
- 数据拷贝
- 利用现有的并行软件构建应用
- 牺牲性能
- 显著的减少开发难度
- 对串行应用进行性能优化
- 提升性能
- 降低能耗
困难点:
- 工作分割
- 不正确的分割选择会导致严重的性能下降
- 通讯开销
- 同步措施
- 并行线程的数量控制
- 过多的线程并发执行,会导致:
- CPU缓存被填满,引起过高的缓存缺失,降低性能
- 带来大量的计算和I/O操作
- 增加程序的状态空间,导致程序难以理解,降低生产率
- 过多的线程并发执行,会导致:
- 并行访问控制
- 一个线程需要的资源:
- 内存数据结构
- CPU
- 内存(缓存)
- I/O设备
- 计算加速器
- 文件
- 网络等其他资源
- 通常引入消息传递机制
- POSIX线程环境
- 结构化查询语言(SQL)
- 分割的全局地址空间环境
- UPC(通用并行C)
- 隐式访问
- 消息传递接口(MPI)
- 显示的消息传递
- 协调方式(同步机制)
- 消息传递
- 加锁
- 事务
- 引用计数
- 显式计时
- 共享原子变量
- 一个线程需要的资源:
- 资源分割和复制
- 通常对写密集型的资源进行分割
- 定期将经常读的资源进行复制
- 与硬件交互
- 榨取系统的最后一点性能
- 考虑
- 缓存结构
- 系统拓扑
- 目标硬件的互联协议
- 配置
- 组合的能力
- 数据并行
- 对数据分割,减少组件内的通信需求
- 分割代码
- 对数据和线程进行映射
- 提升吞吐量
- 减少线程间通信
- 数据并行
- 不正确的分割选择会导致严重的性能下降