OpenMP/概述
本书介绍了 OpenMP,一种 C(和 C++)语言扩展,允许轻松进行并行编程。要理解 OpenMP 的功能,首先需要了解并行编程是什么以及它不是什么。
并行编程 指编写在多个计算设备上同时运行的软件。对于本书而言,“计算设备”主要是处理器(CPU)或多核 CPU 内部的处理器核心,这是 OpenMP 3 的重点。在其他情况下,“计算设备”可能指一个集群中的一台完整计算机,或者其他类型的设备,如图形处理单元(GPU)。英特尔已经设计了 OpenMP 到集群计算的扩展,OpenMP 4 添加了对在非 CPU 设备上执行代码的支持,但这些内容超出了本书的范围。
并行编程主要是为了加速必须快速完成的计算。理想情况下,如果您的程序在n个计算设备(核心)上运行,您希望该程序比在单个设备上运行快n倍。在实践中,这种情况永远不会发生,因为计算设备需要相互通信,发送和等待消息,例如“给我你的计算结果”。尽管如此,并行编程仍然可以将许多应用程序的速度提高到几乎等于n的倍数。
并行编程应该与并发编程区分开来,并发编程意味着将程序分解为概念上同时运行的进程。并行程序和并发程序之间存在相当大的重叠:两者都涉及将任务分解为可以单独执行的不同子任务,并且并发程序可以从在多个计算设备上并行运行其任务中受益。但是,完整的并发编程与并行编程不同,因为通常并发任务之间的通信类型不同于并行任务之间的通信类型。
OpenMP 以非常干净的方式为 C 添加了对并行编程的支持。与线程库不同,现有程序需要进行少量更改才能在多个处理器上并行运行。事实上,OpenMP 的基本结构是如此非侵入性,以至于使用它们但在不支持 OpenMP 的编译器上编译的程序仍然可以工作(尽管是顺序的,当然)。为了了解这意味着什么,请考虑以下 C 函数
void broadcast_sin(double *a, size_t n)
{
#pragma omp parallel for
for (size_t i = 0; i < n; i++) {
a[i] = sin(a[i]);
}
}
此函数在数组上“广播”正弦函数,并将结果存储回同一个数组。当在编译器中启用 OpenMP 时,它实际上将使用多个线程执行此操作,但在没有 OpenMP 的情况下,它仍然可以正常工作并产生完全相同的效果。
OpenMP 程序根据所谓的 分叉-合并模型工作,如右图所示。OpenMP 运行时维护一个线程池,每次遇到并行部分时,它就会将工作分配给池中的线程。当所有线程都完成后,将恢复顺序执行。