并行编程模型

在计算机科学中，并行编程模型（Parallel programming model）是并行计算机架构的抽象化，通过它可方便的表达算法和它们在程序中的合成。判别编程模型的价值可以通过它的通用性：在各种不同架构上能表达多大范围的不同问题，和它的性能：编译的程序在执行时有多高的效率。并行编程模型的实现形式可以是从“顺序编程”语言中调用的函式库，作为现存语言的扩展，或作为全新的语言。

围绕特定编程模型的共识是很重要的，这可导致建造不同的并行计算机来支持这个模型，从而促进软件的可移植性。在这个意义上，编程模型被称为在硬件和软件之间的桥接模型。

## 并行编程模型的分类

并行编程模型的分类可以宽泛的在两个领域主题下进行：进程交互和问题分解。

### 进程交互

进程交互有关于并行进程能够籍此相互通信的机制。最常见的交互形式是共享内存和消息传递。

#### 共享内存

共享内存是在进程间传递数据的高效方式。在共享内存模型中，并行进程共享它们可以异步读与写的全局地址空间。异步并发访问可能导致竞争条件，和用来避免它们的机制如：锁、信号量和监视器。常规的多核处理器直接支持共享内存，很多并行编程语言和库在设计上利用了它，比如采用分叉会合模型的：Cilk、OpenMP和线程建造块。

#### 消息传递

在消息传递模型中，并行进程通过消息传递相互交换数据。这种通信可以是异步的，就是说消息可以在接收者准备好之前发出；或是同步的，就是说消息发出前接收者必须准备好。通信顺序进程（CSP）形式化了使用同步通信通道来连接进程的消息传递，并引出了重要的语言如：Occam、Limbo和Go。与之相对，演员模型使用异步消息传递，并被采用于如下语言的设计中：D、Scala和SALSA。

#### 分布式内存

分布式内存指称一类多处理器计算机系统，其中每个处理器都有自己私有的内存，计算任务只能在本地数据上运算，如果需要远程数据，计算任务必须与一个或多个远程处理器通信。在分布式内存系统编程中的关键要点是如何把数据分布到各个内存上；依赖于所解决的问题，数据可以静态分布，也可以在节点间移动；数据可以在需要时移动，也可以事先推入新的节点。

MPI规定了用于分布式内存系统的通信协议，支持点到点通信和集体通信（collective communication）二者。MPI还是消息传递API，带有对其特征在任何实现中必须如何表现的协议和语义规定。MPI的目标是高性能、可伸缩性和可移植性，目前仍是高性能计算领域中统治性的模型。此外还有支持单边通信（one-sided communication）的分区全局地址空间模型。

### 问题分解

并行程序由同时执行的进程构成。问题分解有关于规划（formulate）成员进程的方式。

#### 数据并行

数据并行模型关注进行运算所在的数据集，典型的是正规结构的数组。一组任务将在这些数据上运算，但是单独的处于在不相交的分区中。数据并行通常对应SPMD编程模型，相应执行模型对应费林分类法中的SIMD（例如AVX处理器补充功能）或MIMD（例如Xeon Phi），还有GPGPU采用的单指令多线程（例如NVIDIA Tesla）。

#### 任务并行

任务并行模型关注进程或线程的执行。这些进程通常表现出独特性，并强调对通信的需求。任务并行是表达消息传递通信的自然方式。任务并行通常对应MPMD编程模型，与SPMD的区别在于适合解决的问题而非执行模型。

### 隐式并行

与上述显式并行相反，隐式并行不向编程者透露任何编译器、运行时系统或硬件负责的事情。例如，在编译器中自动并行化是把顺序代码转变程并行代码的过程；而在计算机架构中，超标量执行是采用指令级并行来进行并行运算的机制，因自身限制而被实际利用为同时多线程/超线程。

在隐式并行中，进程交互对编程者均不可见，转而由编译器和/或运行时系统负责进行交互。函数式编程语言不存在副作用，允许无依赖的函数并行执行，人们已经进行了很多有关的研究实验。以SISAL和SAC为代表的一类数据流程编程语言，是可以高效隐式并行的函数式编程语言，其关键特征是单赋值和面向数组。

## 术语

并行计算模型是计算模型的一大范畴，包括：细胞自动机、PRAM机、LogP机、佩特里网、进程网和交互网模型等。计算模型是用来分析计算进程代价的一种抽象化，利用它并行算法分析性能，可以不取决于特定实现和技术所特有的各种变化，并行算法一般而言是针对特定计算模型而编写的，为PRAM机编写的伪码通常会采用某种For循环形式的并发编程构造。

编程模型指称一种编程样式，即通过看起来像库调用的方式引发执行。例子包括POSIX的Pthreads库和Apache Hadoop中的MapReduce。在这二者情况下，执行模型都符合这个库所用语言的语法却不能按照其语义来理解。不同于计算模型，编程模型特别暗含着对硬件或软件实现的实际考虑。

在并行计算中，执行模型经常必须暴露硬件特征来达成高性能。并行硬件有大量的变种导致了同时需要类似数量的并行执行模型。对每个执行模型都建立一门新语言是不实际的，因此常见的实践都是通过某个API来引发并行执行模型的行为。并行编程语言可以基于一种或一个组合的编程模型。例如，高性能Fortran基于共享内存交互和数据并行问题分解，而Go提供共享内存交互和消息传递交互。

## 并行编程模型

这里列出的编程模型是可称为桥接模型的计算机的抽象模型，它提供了在一个机器的物理实现和编程者可获得的这个机器的抽象概念之间的桥梁；换句话说，它意图在硬件和软件工程师之间提供共同的理解层面。成功的编程模型可以在现实中有效的实现并被编程者有效的作为目标；特别是应当有可能用典型的高级语言编译器生成良好的代码。从编程者的角度来看，这种桥接并行编程模型一般典型的位于Pthreads、IPC、MPI等之上，而在OpenMP、OpenACC等之下。

名称｜交互类别｜分解类别｜实现及用例

分叉会合模型｜共享内存｜数据｜Cilk，OpenMP，线程建造块

整体同步并行模型｜共享内存｜数据｜BSPlib：MulticoreBSP、BSPonMPI，Apache Giraph，Apache Hama

分区全局地址空间模型｜分布式内存｜数据｜SHMEM，协同数组Fortran，Chapel，X10 (编程语言)

通信顺序进程模式｜同步消息传递｜任务｜Occam，Ada，Go

演员模型｜异步消息传递｜任务｜Erlang，D，Scala，很多的框架和库实现

异构计算框架｜共享内存｜数据｜OpenCL，CUDA，SYCL，Pocl

串流处理/数据流程范型｜管道｜数据｜BrookGPU，Apache Flink，RaftLib，TensorFlow，Lustre

高级综合电子设计自动化｜通道｜任务｜C转HDL：Handel-C、SystemC

OpenCL将计算系统视为组成自一组“计算设备”，它们可以是CPU或是附加的“加速器”比如GPU。它定义了一种类C语言用来写程序。在OpenCL设备上执行的函数叫做“内核”。一个单一的计算设备典型的组成自一些“计算单元”，它们依次又包含很多“处理元素”（PE）。一个单一的内核执行可以在所有或多个PE上并行运行。OpenCL定义了API，允许运行于主机上的程序，启动在计算设备上的内核，并管理设备内存，它至少在概念上分离于主机内存。用OpenCL语言写的程序预期会被即时编译，所以使用OpenCL的应用程序在针对各种设备的实现之间是可移植的。

FPGA可以被用来解决任何可计算的问题，这通过用FPGA能实现软微处理器的事实就可轻易的证明。它们的好处在于对某些应用它们明显的要更快速，因为它们有着并行本质和在对用在特定处理上的逻辑门的数目方面的优化。近年来开始兴起使用OpenCL编程来利用FPGA提供的性能和能耗效率。OpenCL允许编程者用C语言编码并把FPGA组合函数作为使用OpenCL构造的OpenCL计算内核的目标。

MapReduce是通过并行、分布式算法在集群上处理和生成键/值对形式的大数据集的编程模型和有关实现，Apache Hadoop中将它与HDFS分立实现。MapReduce受到了在函数式编程范型中常用的map和reduce函数的启发，但是它们在MapReduce框架中的用途不同于它们在起初形式中那样。

并行编程模型还有很多，比如：马里兰大学学院市分校依据PRAM计算模型，建立了指令级并行显式多线程的多处理器计算机和编程语言XMTC，实现了Spawn-Join范型。