并行处理 指的是通过将程序划分为多个可以同时执行的片段,每个片段在自己的处理器上执行,从而加速程序执行的概念。一个在 n 个处理器上执行的程序可能比使用单个处理器快 n 倍。
传统上,多个处理器被提供在专门设计的“并行计算机”中;沿着这个思路,Linux 现在支持 SMP 系统(通常作为“服务器”出售),其中多个处理器在单个计算机内共享单个内存和总线接口。一组计算机(例如,一组各自运行 Linux 的 PC)也可以通过网络互连以形成并行处理集群。使用 Linux 进行并行计算的第三种选择是使用多媒体指令扩展(即 MMX)并行操作整数数据向量。最后,也可以使用 Linux 系统作为专用附加并行处理计算引擎的“主机”。本文档将详细讨论所有这些方法。
尽管使用多个处理器可以加速许多操作,但大多数应用程序尚无法从并行处理中受益。基本上,并行处理仅在以下情况下适用:
好消息是,如果以上所有条件都成立,您会发现使用 Linux 进行并行处理可以为某些执行复杂计算或操作大型数据集的程序带来超级计算机的性能。更重要的是,它可以使用廉价的硬件来做到这一点……您可能已经拥有了这些硬件。额外的好处是,当并行 Linux 系统不忙于执行并行作业时,也很容易将其用于其他事情。
如果并行处理不是您想要的,但您希望至少获得适度的性能提升,那么您仍然可以做一些事情。例如,您可以通过迁移到更快的处理器、添加内存、用快速宽 SCSI 替换 IDE 磁盘等来提高顺序程序的性能。如果这正是您感兴趣的,请跳到 6.2 节;否则,请继续阅读。
尽管并行处理已在许多系统中使用了多年,但大多数计算机用户仍然对此有些陌生。因此,在讨论各种替代方案之前,熟悉一些常用术语非常重要。
SIMD(单指令流,多数据流)指的是一种并行执行模型,其中所有处理器同时执行相同的操作,但每个处理器都允许对其自己的数据进行操作。此模型自然地符合对数组的每个元素执行相同操作的概念,因此通常与向量或数组操作相关联。由于所有操作本质上是同步的,因此 SIMD 处理器之间的交互往往易于且高效地实现。
MIMD(多指令流,多数据流)指的是一种并行执行模型,其中每个处理器本质上是独立运行的。此模型最自然地符合基于功能分解程序以进行并行执行的概念;例如,一个处理器可能更新数据库文件,而另一个处理器生成新条目的图形显示。这是一种比 SIMD 执行更灵活的模型,但它以调试噩梦的风险为代价,称为竞争条件,其中程序可能会由于时序变化而间歇性地失败,从而重新排序一个处理器的操作相对于另一个处理器的操作。
SPMD(单程序,多数据)是 MIMD 的一个受限版本,其中所有处理器都运行相同的程序。与 SIMD 不同,执行 SPMD 代码的每个处理器可能会采用程序中不同的控制流路径。
通信系统的带宽是在单位时间内可以传输的最大数据量……一旦数据传输开始。串行连接的带宽通常以 波特 或 比特/秒 (b/s) 衡量,这通常对应于 字节/秒 (B/s) 的 1/10 到 1/8。例如,1,200 波特调制解调器大约传输 120 B/s,而 155 Mb/s ATM 网络连接快近 130,000 倍,大约传输 17 MB/s。高带宽允许在处理器之间高效地传输大量数据块。
通信系统的延迟是传输一个对象所需的最短时间,包括任何发送和接收软件开销。延迟在并行处理中非常重要,因为它决定了最小的有用粒度,即代码段产生通过并行执行加速的最小运行时间。基本上,如果代码段的运行时间少于传输其结果值的时间(即延迟),则在需要结果值的处理器上串行执行该代码段将比并行执行更快;串行执行将避免通信开销。
消息传递是并行系统中处理器之间交互的模型。通常,消息由一个处理器上的软件构建,并通过互连网络发送到另一个处理器,然后该处理器必须接受并处理消息内容。尽管处理每条消息的开销(延迟)可能很高,但对每条消息可能包含多少信息通常几乎没有限制。因此,消息传递可以产生高带宽,使其成为从一个处理器向另一个处理器传输大量数据块的非常有效的方式。但是,为了最大限度地减少对昂贵的消息传递操作的需求,并行程序中的数据结构必须分布在处理器之间,以便每个处理器引用的大多数数据都在其本地内存中……此任务称为 数据布局。
共享内存是并行系统中处理器之间交互的模型。像运行 Linux 的多处理器奔腾机器这样的系统物理上在它们的处理器之间共享单个内存,以便一个处理器写入共享内存的值可以被任何处理器直接访问。或者,逻辑上共享内存可以在每个处理器都有自己的内存的系统中实现,方法是将每个非本地内存引用转换为适当的处理器间通信。共享内存的任一实现通常都被认为比消息传递更容易使用。物理共享内存可以同时具有高带宽和低延迟,但仅当多个处理器不尝试同时访问总线时;因此,数据布局仍然会严重影响性能,并且缓存效应等会使确定最佳布局变得困难。
在消息传递和共享内存模型中,通信由单个处理器启动;相比之下,聚合函数通信是一种本质上并行的通信模型,其中整个处理器组协同工作。最简单的此类操作是 屏障同步,其中每个单独的处理器都等待直到组中的每个处理器都到达屏障。通过让每个处理器在到达屏障时输出一个数据,可以使通信硬件向每个处理器返回一个值,该值是根据从所有处理器收集的值的任意函数。例如,返回值可能是问题“是否有任何处理器找到解决方案?”的答案,或者它可能是来自每个处理器的一个值的总和。延迟可能非常低,但每个处理器的带宽也往往较低。传统上,此模型主要用于控制并行执行,而不是分发数据值。
这是聚合函数的另一个名称,最常用于指代使用多个消息传递操作构建的聚合函数。
SMP(对称多处理器)指的是一组处理器作为对等方协同工作的操作系统概念,以便任何工作都可以由任何处理器同样出色地完成。通常,SMP 意味着 MIMD 和共享内存的组合。在 IA32 世界中,SMP 通常意味着符合 MPS(英特尔多处理器规范);在未来,它可能意味着“Slot 2”……
SWAR(寄存器内 SIMD)是通用术语,指的是将寄存器划分为多个整数字段,并使用寄存器宽度操作在这些字段上执行 SIMD 并行计算的概念。给定一台具有 k 位寄存器、数据路径和功能单元的机器,长期以来人们都知道,普通寄存器操作可以用作多达 n 个、k/n 位字段值的 SIMD 并行操作。尽管可以使用普通整数寄存器和指令来实现这种类型的并行性,但许多高端微处理器最近添加了专门的指令来增强这种技术在面向多媒体任务方面的性能。除了英特尔/AMD/Cyrix MMX(多媒体扩展)之外,还有:Digital Alpha MAX(多媒体扩展)、惠普 PA-RISC MAX(多媒体加速扩展)、MIPS MDMX(数字媒体扩展,发音为“Mad Max”)和 Sun SPARC V9 VIS(视觉指令集)。除了在 MMX 上达成一致的三家供应商之外,所有这些指令集扩展都大致相当,但彼此不兼容。
附加处理器本质上是连接到 主机 系统的专用计算机,用于加速特定类型的计算。例如,用于 PC 的许多视频和音频卡都包含附加处理器,分别旨在加速常见的图形操作和音频 DSP(数字信号处理)。还有各种各样的附加 阵列处理器,之所以这样称呼它们是因为它们旨在加速数组上的算术运算。事实上,许多商业超级计算机实际上是带有工作站主机的附加处理器。
RAID(廉价磁盘冗余阵列)是一种简单的技术,用于提高磁盘 I/O 的带宽和可靠性。尽管有很多不同的变体,但所有变体都有两个共同的关键概念。首先,每个数据块都条带化到一组 n+k 个磁盘驱动器上,这样每个驱动器只需读取或写入 1/n 的数据……产生一个驱动器的 n 倍带宽。其次,写入冗余数据,以便在磁盘驱动器发生故障时可以恢复数据;这很重要,因为否则,如果 n+k 个驱动器中的任何一个发生故障,则整个文件系统可能会丢失。关于 RAID 的总体概述,请访问 http://www.uni-mainz.de/~neuffer/scsi/what_is_raid.html,有关 Linux 系统 RAID 选项的信息,请访问 http://linas.org/linux/raid.html。除了专门的 RAID 硬件支持外,Linux 还支持跨单个 Linux 系统托管的多个磁盘的软件 RAID 0、1、4 和 5;有关详细信息,请参阅软件 RAID mini-HOWTO 和多磁盘系统调优 mini-HOWTO。集群中多台机器上的磁盘驱动器之间的 RAID 不被直接支持。
IA32(英特尔架构,32 位)实际上与并行处理无关,而是指指令集通常与英特尔 386 兼容的处理器类别。基本上,286 之后的任何英特尔 x86 处理器都与表征 IA32 的 32 位平面内存模型兼容。AMD 和 Cyrix 也制造了大量的 IA32 兼容处理器。由于 Linux 主要在 IA32 处理器上发展起来,并且商品市场也集中在那里,因此使用 IA32 来区分任何这些处理器与 PowerPC、Alpha、PA-RISC、MIPS、SPARC 等处理器是很方便的。即将推出的 IA64(64 位,带 EPIC,显式并行指令计算)肯定会使情况复杂化,但第一款 IA64 处理器 Merced 计划在 1999 年才投产。
自从许多并行超级计算机公司倒闭以来,COTS(商用现成品)通常被讨论为并行计算系统的要求。如果过于纯粹地看待,使用 PC 的唯一 COTS 并行处理技术是 SMP Windows NT 服务器和各种 MMX Windows 应用程序之类的东西;过于狂热真的没有必要。COTS 的基本概念实际上是最大限度地减少开发时间和成本。因此,COTS 更有用、更常见的含义是,至少大多数子系统受益于商品营销,但在其他技术有效的地方使用它们。最常见的,COTS 并行处理指的是集群,其中节点是商品 PC,但网络接口和软件在某种程度上是定制的……通常运行 Linux 和应用程序代码,这些代码是免费提供的(例如,copyleft 或公共领域),但并非字面意义上的 COTS。
为了更好地理解本 HOWTO 中概述的各种并行编程方法的使用,有一个示例问题很有用。尽管几乎任何简单的并行算法都可以做到这一点,但通过选择一种已用于演示各种其他并行编程系统的算法,可以更容易地比较和对比各种方法。M. J. Quinn 的著作《并行计算理论与实践》,第二版,McGraw Hill,纽约,1994 年,使用了一种计算 Pi 值的并行算法来演示各种不同的并行超级计算机编程环境(例如,nCUBE 消息传递,Sequent 共享内存)。在本 HOWTO 中,我们使用相同的基本算法。
该算法通过对 x 平方下的面积求和来计算 Pi 的近似值。作为一个纯粹的顺序 C 程序,该算法看起来像
#include <stdlib.h>; #include <stdio.h>; main(int argc, char **argv) { register double width, sum; register int intervals, i; /* get the number of intervals */ intervals = atoi(argv[1]); width = 1.0 / intervals; /* do the computation */ sum = 0; for (i=0; i<intervals; ++i) { register double x = (i + 0.5) * width; sum += 4.0 / (1.0 + x * x); } sum *= width; printf("Estimation of pi is %f\n", sum); return(0); }
但是,这种顺序算法很容易产生“令人尴尬的并行”实现。该区域被细分为间隔,并且任意数量的处理器可以各自独立地对其分配的间隔求和,而无需处理器之间的交互。一旦计算出局部和,它们就会被加在一起以创建全局和;此步骤需要处理器之间的一定程度的协调和通信。最后,此全局和由一个处理器打印为 Pi 的近似值。
在本 HOWTO 中,此算法的各种并行实现出现在讨论每种不同编程方法的地方。
本文档的其余部分分为五个部分。第 2、3、4 和 5 节对应于使用 Linux 支持并行处理的三种不同类型的硬件配置
本文档的最后一节涵盖了对使用 Linux 进行并行处理具有普遍意义的方面,而不是特定于上面列出的方法之一。
当您阅读本文档时,请记住我们尚未测试所有内容,并且此处报告的许多内容“仍然具有研究性质”(一种委婉的说法,表示“并非完全像它应该的那样工作”;-)。但是,使用 Linux 进行并行处理现在很有用,并且越来越多的人正在努力使其变得更好。
本 HOWTO 的作者是 Hank Dietz 博士,现任肯塔基大学教授兼 James F. Hardymon 网络工程讲席教授,地址:肯塔基州列克星敦市电气与计算机工程系,邮编 40506-0046。Dietz 根据 Linux 文档项目指南保留本文档的权利。尽管已努力确保本演示文稿的正确性和公正性,但 Dietz 和肯塔基大学均不对任何问题或错误负责,并且肯塔基大学不认可所讨论的任何工作/产品。