【高性能计算背景】《并行计算教程简介》翻译 - 中文 - 3 / 4


一、写在前面

并行计算的入门文章非劳伦斯利弗莫尔国家实验室(LLNL)《Introduction to Parallel Computing Tutorial》[1]所属,于是本着学习的态度,笔者对其进行了翻译,以下是《Introduction to Parallel Computing Tutorial》的中文版,篇幅限制,本篇博客仅包含E. 设计并行程序部分,为《Introduction to Parallel Computing Tutorial》的第三部分,共四部分。

【高性能计算背景】《并行计算教程简介》翻译 - 中文 - 1 / 4
【高性能计算背景】《并行计算教程简介》翻译 - 中文 - 2 / 4
【高性能计算背景】《并行计算教程简介》翻译 - 中文 - 3 / 4
【高性能计算背景】《并行计算教程简介》翻译 - 中文 - 4 / 4


二、摘要

这是“利弗莫尔计算入门”研讨会的第一篇教程。本文旨在简要概述并行计算这一广泛而宽泛的主题,作为后续教程的导读。因此,它只涵盖并行计算的基本知识,面向刚刚熟悉该主题并计划参加本研讨会的一个或多个其他教程的人。它并不打算深入讨论并行编程,因为这将需要更多的时间。本教程首先讨论并行计算 - 它是什么以及如何使用,然后讨论与并行计算相关的概念和术语。然后探讨了并行内存体系结构和编程模型的主题。这些主题之后是一系列关于设计和运行并行程序的复杂问题的实际讨论。本教程最后给出了几个如何并行处理几个简单问题的示例。包括参考文献,以供进一步自学。

A. 并行计算概述

1. 什么是并行计算?

2. 为什么使用并行计算?

3. 谁在使用并行计算?


B. 概念和术语

1. 冯诺依曼计算机体系结构

2. 弗林分类法

3. 通用并行计算术语

4. 并行编程的潜在好处、限制和成本


C. 并行计算机内存架构

1. 共享内存

2. 分布式内存

3. 混合分布式共享内存


D. 并行编程模型

1. 共享内存模型

2. 线程模型

3. 分布式内存/消息传递模型

4. 数据并行模型

5. 混合模型

6. SPMD 和 MPMP


E. 设计并行程序

1. 自动并行 vs. 手动并行

  • 设计和开发并行程序一直是一个非常手工的过程。程序员通常负责识别和实际实现并行性。
  • 通常,手动开发并行代码是一个耗时、复杂、易出错和迭代的过程。
  • 多年来,各种工具都可以帮助程序员将串行程序转换为并行程序。用于自动并行化串行程序的最常见工具是并行化编译器预处理器
  • 并行化编译器通常以两种不同的方式工作:

全自动

  • 编译器分析源代码并确定并行性的机会。
  • 该分析包括识别并行性的阻碍因素,并可能对并行性是否会真正提高性能进行成本加权。
  • 循环(do,for)是自动并行化最常见的目标。

程序员指导

  • 程序员使用编译器指令或可能的编译器标志,显式地告诉编译器如何并行化代码。
  • 也可以与某种程度的自动并行化结合使用。
  • 最常见的编译器生成的并行化是使用节点共享内存和线程(如OpenMP)完成的。
  • 如果您是从一个现有的串行代码开始的,并且有时间或预算限制,那么自动并行可能是答案。然而,自动并行化有几个重要的注意事项:
    • 可能会产生错误的结果
    • 性能实际上可能会降低
    • 比手动并行灵活得多
    • 仅限于代码的子集(主要是循环)
    • 如果编译器分析表明存在抑制器(inhibitor)或代码太复杂,可能实际上无法并行化代码
      本节其余部分适用于开发并行代码的手动方法。

2. 理解问题和程序

程序=算法+数据+(硬件)
在这里插入图片描述

确定问题是否可以实际并行化 👆

  • 毫无疑问,开发并行软件的第一步是首先理解您希望并行解决的问题。如果您是从串行程序开始的,这意味着也要理解现有代码。

  • 在花时间尝试开发问题的并行解决方案之前,请确定该问题是否确实可以并行化。

    • 一个易于并行化的问题示例:
      计算一个分子数千个独立构象中每一个构象的势能。完成后,找到最小能量构象。
      这个问题可以并行解决。每个分子构象都是可以独立确定的。最小能量构象的计算也是一个可并行化的问题。
    • 很少或没有并行性的问题和算法示例:
      Fibonacci级数前10000个成员的计算(0,1,1,2,3,5,8,13,21,…)使用以下公式: F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) Fn=Fn1+Fn2
      F ( n ) F(n) Fn值的计算使用 F ( n − 1 ) F(n-1) Fn1 F ( n − 2 ) F(n-2) Fn2的值,必须首先计算这些值。
      解决此问题的并行算法示例(使用Binet公式):
      在这里插入图片描述
      其中
      在这里插入图片描述
  • 确定程序的热点

    • 知道大部分实际工作在哪里进行。大多数科技程序通常在少数几个地方完成大部分工作。
    • 探查器和性能分析工具可以在这里提供帮助。
    • 关注热点的并行化,忽略那些占用很少CPU的程序部分。
      确定程序中的瓶颈
    • 是否存在速度异常缓慢的区域,或者导致可并行工作暂停或延迟?例如,输入/输出通常会减慢程序的速度。
    • 可以重组程序或使用不同的算法来减少或消除不必要的慢速区域。
  • 识别平行性的阻碍因素。一种常见的抑制物是数据依赖,如上面的斐波那契序列所示。

  • 如果可能请调研其他算法。在设计并行应用程序时,这可能是一个最重要的考虑因素。

  • 利用一流供应商(IBM的ESSL、Intel的MKL、AMD的AMCL等)提供的优化的第三方并行软件和高度优化的数学库。

3. 分解

  • 设计并行程序的第一步是将问题分解为可分配给多个任务的离散工作。这称为分解或分区。
  • 在并行任务之间划分计算工作有两种基本方法:空间域分解功能分解

空间域分解
在这种类型的分解中,与问题相关的数据被分解。然后,每个并行任务处理一部分数据。
在这里插入图片描述

空间域分解 👆

有不同的方法可以对数据进行分区:

在这里插入图片描述

分解例子 👆

功能分解
在这种方法中,重点是要执行的计算,而不是由计算操作的数据。根据必须完成的工作分解问题。然后,每个任务执行总体工作的一部分。
在这里插入图片描述

功能分解 👆

功能分解可以很好地解决可分为不同任务的问题。例如:
生态系统建模
每个程序计算给定组的群体,其中每个组的增长取决于其邻居的增长。随着时间的推移,每个进程都会计算其当前状态,然后与邻居群体交换信息。然后,所有任务都会在下一个时间步计算状态。
在这里插入图片描述

生态系统建模 👆

信号处理
音频信号数据集通过四个不同的计算滤波器。每个滤波器都是一个单独的过程。第一段数据必须先通过第一个滤波器,然后才能进入第二个滤波器。当它这样做时,第二段数据将通过第一个滤波器。当第四段数据进入第一个滤波器时,所有四个任务都处于繁忙状态。
类似流水线的思想
在这里插入图片描述

信号处理 👆

气候模拟
每个模型组件都可以看作是一个单独的任务。箭头表示计算期间组件之间的数据交换:大气模型生成海洋模型使用的风速数据,海洋模型生成大气模型使用的海面温度数据,等等。
在这里插入图片描述

气候建模 👆

在这里插入图片描述

气候和大气模拟组件之间的复杂关系 👆

  • 将这两种类型的问题分解结合在一起是常见且自然的。

4. 通讯

谁需要通信?
任务之间是否需要通信取决于你的问题:
你不需要通信

  • 某些类型的问题可以并行分解和执行,实际上不需要任务共享数据。这些类型的问题通常被称为理想并行(前文提到的“embarrassingly parallel”,记得吗?)问题——几乎不需要或根本不需要通信。
  • 例如,想象一个图像处理操作,其中黑白图像中的每个像素都需要反转其颜色。图像数据可以轻松地分配到多个任务,然后这些任务相互独立地执行各自的部分工作。
    在这里插入图片描述

无需大量通信的并行处理 👆

你需要通信

  • 大多数并行应用程序都不是那么简单,确实需要任务之间彼此共享数据。
  • 例如,二维热扩散问题要求任务知道由具有相邻数据的任务计算的温度。对相邻数据的更改会直接影响该任务的数据。
    在这里插入图片描述

需要大量通信的并行处理 👆

需要考虑的因素
在设计程序的任务间通信时,有许多重要因素需要考虑:
通信开销
在这里插入图片描述

通信是复杂的 👆

  • 任务间通信实际上总是意味着开销。
  • 可以用于计算的机器周期和资源被用来打包和传输数据。
  • 通信经常需要任务之间进行某种类型的同步,这可能导致任务花费时间等待而不是工作。
  • 相互竞争的通信流量会使可用的网络带宽饱和,从而进一步加剧性能问题。

延迟与带宽

  • 延迟是从点a向点B发送最小(0字节)消息所需的时间。通常以微秒表示。
  • 带宽是指单位时间内可以传输的数据量。通常表示为兆字节/秒或千兆字节/秒。
  • 发送许多小消息可能会导致延迟控制通信开销。通常,将较小的消息打包成较大的消息更有效,从而增加有效的通信带宽。

通信可见性

  • 使用消息传递模型,通信是显式的,并且通常非常可见,并且在程序员的控制下。
  • 对于数据并行模型,通信通常对程序员不透明,尤其是在分布式内存体系结构上。程序员甚至可能无法确切知道任务间通信是如何完成的。

同步与异步通信

  • 同步通信需要在共享数据的任务之间进行某种类型的握手。这可以由程序员在代码中显式构造,也可以发生在程序员未知的较低级别。
  • 同步通信通常被称为阻塞通信,因为其他工作必须等待通信完成。
  • 异步通信允许任务相互独立地传输数据。例如,任务1可以准备并向任务2发送消息,然后立即开始执行其他工作。任务2何时实际收到数据并不重要。
  • 异步通信通常被称为非阻塞通信,因为在通信过程中可以完成其他工作。
    将计算与通信交织是使用异步通信的最大好处。

通信范围

  • 在并行代码的设计阶段,了解哪些任务必须相互通信是至关重要的。下面描述的两个范围都可以同步或异步实现。
  • 点到点 - 涉及两个任务,一个任务充当数据的发送者/生产者,另一个任务充当接收者/消费者。
  • 集合 - 涉及两个以上任务之间的数据共享,这些任务通常被指定为公共组或集合中的成员。一些常见的变体(还有更多):

在这里插入图片描述

不同类型的通信范围 👆

通信效率

  • 通常,程序员有可能影响通信性能的选择。这里只提到几个。
  • 给定模型应使用哪种实现?以消息传递模型为例,一个MPI实现在给定硬件平台上可能比另一个更快。
  • 应该使用什么类型的通信操作?如前所述,异步通信操作可以提高总体程序性能。
  • 网络结构不同的平台使用不同的网络。一些网络的性能优于其他网络。选择网络速度更快的平台可能是一种选择。

开销和复杂性

在这里插入图片描述

并行通信开销和复杂性示例 👆

最后,要意识到这只是需要考虑的事情的一部分!

5. 同步

  • 对大多数并行程序来说,管理工作顺序和执行它的任务是一个重要的设计考虑因素。
  • 可能是程序性能的重要因素(或缺乏它)
  • 通常需要对程序段进行“序列化”。
    在这里插入图片描述

并行处理中任务的同步是一个重要的设计考虑因素 👆

同步的类型
屏障

  • 通常意味着涉及所有任务
  • 每个任务都会执行自己的工作,直到到达屏障。然后停止,或“阻塞”。
  • 当最后一个任务到达屏障时,所有任务都将同步。
  • 从这里发生的事情各不相同。通常,必须完成一系列的工作。在其他情况下,任务会自动释放以继续其工作。

锁/信号量

  • 可以涉及任意数量的任务
  • 通常用于串行(保护)对全局数据或一段代码的访问。一次只能有一个任务可以使用(拥有)锁/信号量/标志。
  • 获取锁的第一个任务“设置”它。然后,此任务可以安全地(串行地)访问受保护的数据或代码。
  • 其他任务可以尝试获取锁,但必须等待拥有该锁的任务释放该锁。
  • 可以是阻塞或非阻塞。

同步通信操作

  • 只涉及那些执行通信操作的任务。
  • 当任务执行通信操作时,需要与参与通信的其他任务进行某种形式的协调。例如,在任务可以执行发送操作之前,它必须首先从接收任务接收到可以发送的确认。
  • 在前面通信部分已讨论过。

6. 数据依赖

定义

  • 当语句执行顺序影响程序结果时,程序语句之间存在依赖关系。
  • 不同的任务多次使用存储中的相同位置会导致数据依赖
  • 依赖对并行编程很重要,因为它们是并行性的主要障碍之一。

在这里插入图片描述

依赖可视化 👆

举例
循环携带数据相关性

    DO J = MYSTART,MYEND
       A(J) = A(J-1) * 2.0
    END DO
  • A(J-1)的值必须在A(J)的值之前计算,因此A(J)表现出对A(J-1)的数据依赖性。并行性被抑制。
  • 如果任务2有A(J)且任务1有A(J-1),则计算A(J)的正确值需要:
    • 分布式内存体系结构——任务1完成计算后,任务2必须从任务1获取A(J-1)的值
    • 共享内存体系结构——任务1更新后,任务2必须读取A(J-1)

与循环无关的数据相关性

    task 1        task 2
    ------        ------

    X = 2         X = 4
      .             .
      .             .
    Y = X**2      Y = X**3
  • 与前一个示例一样,并行性被抑制。Y的值取决于:
    • 分布式内存体系结构——是否或何时X的值在任务之间被通信。
    • 共享内存体系结构——哪个任务最后存储X的值。
      虽然在设计并行程序时,识别所有数据依赖关系都很重要,但循环携带的依赖关系尤其重要,因为循环可能是并行化工作最常见的目标。

如何处理数据依赖

  • 分布式内存体系结构——在同步点传输所需的数据。
  • 共享内存体系结构——同步任务之间的读/写操作。

7. 负载均衡

  • 负载平衡是指在任务之间分配大致相等的工作量,以便所有任务始终处于繁忙状态。可以将其视为任务空闲时间的最小化。
  • 出于性能原因,负载平衡对于并行程序很重要。例如,如果所有任务都受屏障同步点的约束,则最慢的任务将决定总体性能。

在这里插入图片描述
在这里插入图片描述

如何实现负载均衡
平均分配每个任务收到的​​工作

  • 对于每个任务执行类似工作的数组/矩阵操作,请将数据集均匀分布在任务之间。
  • 在对于循环迭代中每个迭代完成的工作量相似,请将迭代均匀地分布到各个任务中。
  • 如果使用具有不同性能特征的机器的异构组合,请确保使用某种类型的性能分析工具来检测任何负载不平衡。相应地调整工作。

使用动态工作分配

  • 即使数据在任务之间均匀分布,某些类型的问题也会导致负载不平衡:
    在这里插入图片描述

稀疏数组——一些任务将有实际数据来处理,而另一些任务则大多是。👆

在这里插入图片描述

自适应网格方法——一些任务可能需要细化它们的网格,而另一些则不需要。👆

当每个任务将执行的工作量难以确定的或无法预测时,使用调度器任务池方法可能会有所帮助。当每个任务完成其工作时,它将从工作队列接收一个新的工作。

在这里插入图片描述

调度器-任务池 👆

最终,可能需要设计一种算法来检测和处理代码中动态发生的负载不平衡。

8. 粒度

计算/通信比

  • 在并行计算中,粒度是计算与通信比率的定性度量。
  • 计算周期通常通过同步事件与通信周期分离。

细粒度并行

  • 在通信事件之间完成相对少量的计算工作。
  • 计算与通信的比率低。
  • 促进负载平衡。
  • 意味着较高的通信开销和较少的性能增强机会。
  • 如果粒度太细,则任务之间的通信和同步所需的开销可能比计算时间长。
    在这里插入图片描述

细粒度并行 👆

粗粒度并行

在这里插入图片描述

粗粒度并行 👆

  • 在通信/同步事件之间完成了相对大量的计算工作
  • 高计算通信比
  • 意味着更多的性能提升机会
  • 更难有效地进行负载平衡

哪种是最好的?

  • 最有效的粒度取决于算法及其运行的硬件环境。
  • 在大多数情况下,与通信和同步相关的开销相对于执行速度而言很高,因此具有粗粒度是有利的。
  • 细粒度并行有助于减少负载不平衡导致的开销。

9. I/O

坏消息
在这里插入图片描述

I/O操作 👆

  • I/O操作通常被视为并行性的阻碍因素。
  • I/O操作需要的时间比内存操作多几个数量级。
  • 并行I/O系统可能不成熟或不适用于所有平台。
  • 在所有任务都看到相同文件空间的环境中,写入操作可能会导致文件覆盖。
  • 文件服务器同时处理多个读取请求的能力可能会影响读取操作。
  • 必须通过网络(NFS、非本地)进行的I/O可能会导致严重的瓶颈,甚至导致文件服务器崩溃。

好消息

  • 并行文件系统可用。例如:
    GPFS:通用并行文件系统 (IBM)。现在称为 IBM Spectrum Scale。
    Lustre:适用于 Linux 集群(英特尔)
    HDFS:Hadoop 分布式文件系统 (Apache)
    PanFS:适用于 Linux 集群的 Panasas ActiveScale 文件系统 (Panasas, Inc.)
    以及更多——请参阅http://en.wikipedia.org/wiki/List_of_file_systems#Distributed_parallel_file_systems

  • MPI 的并行 I/O 编程接口规范自 1996 年起作为 MPI-2 的一部分提供。供应商和免费实现现在普遍可用。
    几点建议:

  • 规则 #1:尽可能减少整体 I/O。

  • 如果您有权访问并行文件系统,请使用它。

  • 写入大块数据而不是小块数据通常效率更高。

  • 更少、更大的文件比许多小文件的性能更好。

  • 将 I/O 限制在作业的特定串行部分,然后使用并行通信将数据分配给并行任务。例如,任务 1 可以读取输入文件,然后将所需的数据传递给其他任务。同样,任务 1 可以在从所有其他任务接收到所需数据后执行写操作。

  • 跨任务聚合 I/O 操作——与其让许多任务执行 I/O,不如让一部分任务执行它。

10. 调试

  • 调试并行代码可能非常困难,尤其是当代码向上扩展时。
  • 好消息是,有一些优秀的调试器可以提供帮助:
    • Threaded - pthreads and OpenMP
    • MPI
    • GPU / accelerator
    • Hybrid
  • 利弗莫尔计算用户可以访问安装在LC集群上的多个并行调试工具:
    • TotalView from RogueWave Software
    • DDT from Allinea
    • Inspector from Intel
    • Stack Trace Analysis Tool (STAT) - locally developed at LLNL
  • 所有这些工具都有一条与之相关的学习曲线。
  • 有关详细信息和入门信息,请参阅:

在这里插入图片描述

使用调试工具 👆

11. 性能分析和调优

在这里插入图片描述

使用性能分析和调优工具 👆


F. 并行示例

1. 数组处理

2. 计算PI

3. 简单热方程

4. 一维波动方程


G. 参考资料和更多信息


四、总结

以上就是今天要分享的内容,本章的内容也让笔者受益匪浅,已经迫不及待准备翻译F. 并行示例了,本文翻译了《并行计算教程简介》的E章节,笔者一人翻译难免有翻译的不足之处,望海涵 😐 。
如果本文能给你带来帮助的话,点个赞鼓励一下作者吧! 😐


五、参考

[1] Lawrence Livermore National Laboratory:https://hpc.llnl.gov/documentation/tutorials/introduction-parallel-computing-tutorial

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值