对线程级的并行提供硬件或者软件上的支持:
一种方法就是采用抢占式或时间片轮转的多任务操作系统。这种方法允许用当前的软件中日益增多的并发性。采用时间版策略的多线程方法允许开发人员通过在多个线程之间切换执行的途径达到了隐藏I/O延迟的目的。实际上,这种模式并不支持并行执行,因为在任何时间,CPU都只能执行一个指令流。
另一种方法就是增加计算机中物理处理器的数量,这种方法能够有效利用线程级并行性。多处理器系统支持真正意义上的并行执行,因为多个线程或者进程能够在多个处理器上同时执行。不过这种方法会增加整个系统的造价。
线程,可以定义成CPU资源占用的一个基本单位,包括指向指令流中当前指令的程序计数器、当前线程的CPU状态信息以及一些其他资源,比如堆栈。
实际的处理器是由大量不同的资源所组成的,包括体系结构状态——通用CPU寄存器和中断控制寄存器、cache、总线、执行单元,以及分支预测逻辑等等。但是,要定义一个线程,只需要体系结构状态信息即可。四级,通过复制这些体系结构状态信息即可。因此,通过复制这些体系结构状态信息的方法就能够创建多个逻辑处理器(或者线程)。然后,执行资源就被告不同的逻辑处理器所共享。这种技术就是众所周知的同时多线程技术(Simultaneous Multi-Threading,SMT)技术。
单核处理器只能将多个指令流交错执行,并不能真正地让它们同时执行。
可以视并行应用程序为众多相互依赖的任务的集合,将应用程序划分成多个独立的任务,并确定这些任务之间的相互依赖关系的过程就被称为分解(decomposition)。分解问题的方式主要有三种:任务分解、数据分解、数据流分解。
主要分解方式总结
分解方式 | 设计 | 说明 |
任务分解 | 不同的程序行为采用不同的线程实现 | 常用于GUI应用程序 |
数据分解 | 多个线程对不同的数据块执行相同的操作 | 常用于音频、图像处理和科学计算机应用程序 |
数据流分解 | 一个线程的输出作为另一个线程的输入 | 尤其就注意尽量消除启动和排空延迟 |
任务分解
对应用程序根据其执行的功能进行分解的过程称为任务分解(task decomposition)。任务分解是一种能够简单实现并行执行的方法。根据这种方法我们能够对众多的独立任务进行分类。如果其中两个任务能够同时运行,那么开发人员,形成二者之间的并发执行。但是,一般情况下,开发人员需要对通过任务分解出来的任务进行一些修改,从而避免他们之间的冲突,并且标识这些任务不再是串行执行。
数据分解
数据分解也称为数据级并行(data-level parallelism),是将应用程序根据各任务处理的数据而非按任务的天然特性来进行分解的方法。一般来讲,能够按照数据分解方式进行分解的应用程序都饮食多个线程,这些线程分别对不同的数据对象执行相同的操作。
数据流分解
很多情况下,当对一个问题进行分解的时候,关键问题不在于采用一些什么任务来完成这个工作,而在于数据在这些任务之间是如何流动的。这种时候就需要采用数据流分解方式,根据任务之间的数据流关系对问题进行分解。
数据流关系影响程序并行执行效率的一个例子就是众所周知的生产者/消费者(producer/consumer)问题。在这个问题里面,一个任务(称为生产者)的输出是另一个任务(消费者)的输入。如果将两个任务采用不同的线程并行执行,那么消费者线程需要一直等到生产者完成其工作(或部分工作)的时候才能开始执行。