认识并行计算和python
并行计算的内存架构分类:
-
单处理器,单数据(SISD)
传统的单处理器计算机都是经典的SISD系统。
-
单处理器,多数据 (SIMD)
SIMD计算机包括多个独立的处理器,每一个都有自己的局部内存,可以用来存储数据。GPU就是内置了很多个SIMD处理单元,使这种架构在今天应用非常广泛。
-
多处理器,单数据 (MISD)
MISD在现实中并没有很多用武之地,更多的是作为一个抽象模型的存在。
-
多处理器,多数据 (MIMD)
这种计算机是最广泛使用、也是最强大的一个种类。这种架构有n个处理器,n个指令流,n个数据流。但是异步的算法非常难设计、分析和实现。
内存管理:
内存管理是并行架构需要考虑的另一方面,确切来说是获得数据的方式。无论处理单元多快,如果内存提供指令和数据的速度跟不上,系统性能也不会得到提升。制约内存达到处理器速度级别的响应时间的主要因素是内存存取周期。所谓存取周期就是连续启动两次读或写操作所需间隔的最小时间。
-
共享内存
-
分布式内存
并行编程模型
并行编程模型是作为对硬件和内存架构的抽象而存在的。使用范围最广的并行编程模型有:
-
共享内存模型
在这个编程模型中所有任务都共享一个内存空间,对共享资源的读写是 异步的。系统提供一些机制,如锁和信号量,来让程序员控制共享内存的访问权限。使用这个编程模型的优点是,程序员不需要清楚任务之间通讯的细节。但性能方面的一个重要缺点是,了解和管理数据区域变得更加困难;将数据保存在处理器本地才可以节省内存访问,缓存刷新以及多处理器使用相同数据时发生的总线流量。
-
多线程模型
-
分布式内存/消息传递模型
消息传递模型通常在分布式内存系统(每一个处理器都有独立的内存空间)中应用。MPI(the Message Passing Interface, 消息传递接口) 模型是专门为分布式内存设计的,但作为一个并行编程模型,也可以在共享内存机器上跨平台使用。
-
数据并行模型
在这个模型中,有多个任务需要操作同一个数据结构,但每一个任务操作的是数据的不同部分。在共享内存架构中,所有任务都通过共享内存来访问数据;在分布式内存架构中则会将数据分割并且保存到每个任务的局部内存中。为了实现这个模型,程序员必须指定数据的分配方式和对齐方式。现代的GPU在数据已对齐的情况下运行的效率非常高。
### 设计一个并行程序的步骤
并行算法的设计是基于一系列操作的,在编程的过程中必须执行这些操作来准确地完成工作而不会产生部分结果或错误结果。并行算法地大致操作如下:
- 任务分解 (Task decomposition)
- 任务分配 (Task assignment)
- 聚合 (Agglomeration)
- 映射 (Mapping)
**任务分解**
第一阶段,将软件程序分解为可以在不同处理器执行的多个任务或一系列指令以实现并行性。下面展示了两个方法来实现程序分解:
- 按范围分解 (Domain decomposition):使用这个分解方法,程序所需的数据会被分解;处理器会使用同一个程序处理不同的数据。这个方法一般在需要处理大量数据的情况下使用。
- 按功能分解 (Functional decomposition):使用这个分解方法会将问题分解为几个任务,每个任务会对可利用的数据执行不同的操作。
****任务分配****
并行程序将任务分配给各种处理器的机制是确定的。这个阶段非常重要,因为在这阶段会向各个处理器之间分配工作。负载均衡是这个阶段的关键,所有处理器都应该保持工作状态,避免长时间的空闲。
****聚合****
聚合,就是为了提升性能将小任务合并成大任务的过程。如果设计过程的前两个阶段是将分解问题得到的任务数量大大超过处理器可接受的程度,或者计算机不是专门设计用于处理大量小任务 (如GPU的架构就非常适合处理数百万甚至上亿任务),那么过分解会导致严重的效率下降。
****映射****
在并行算法设计的映射阶段,会指定任务由哪个处理器处理。这阶段的目标是减少总体的执行时间。在这里需要经常做取舍,因为下面两个相互矛盾的策略:
- 需要频繁通讯的任务应该由同一个处理器处理以增强局部性。
- 可以并行执行的任务应该由多个处理器处理以增强并行性。