类比:洗衣服
想象一下拥有以下设施的干洗店:挂脏衣服或干净衣服的架子、洗衣机和烘干机(每台都可以一次洗一件衣服)、折叠桌和熨衣板。
负责所有实际洗涤和烘干的服务员相当愚蠢,因此接受干洗订单的店主特别小心,非常仔细和明确地写下每条指令。
在典型的一天,这些说明可能类似于:
- 从架子上拿衬衫
- 洗衬衫
- 把衬衫擦干
- 熨烫衬衫
- 把衬衫叠起来
- 把衬衫放回架子上
- 从架子上拿裤子
- 洗裤子
- 把裤子擦干
- 把裤子叠起来
- 把裤子放回架子上
- 从架子上取下外套
- 洗外套
- 把外套擦干
- 熨烫外套
- 把外套放回架子上
服务员按照这些指示前往发球台,非常小心不要做任何不正常的事情。可以想象,洗完一天的衣物需要很长时间,因为要彻底清洗、烘干和折叠每件衣物需要很长时间,而且必须一次完成。
但是,有一天服务员辞职了,并聘请了一位新的、更聪明的服务员,他注意到大多数设备在一天中的任何特定时间都处于闲置状态。当裤子在烘干时,熨衣板和洗衣机都没有使用。所以他决定更好地利用他的时间。因此,他会这样做,而不是上述一系列步骤:
- 从架子上拿衬衫
- 洗衬衫,从架子上拿裤子
- 擦干衬衫,洗裤子
- 熨烫衬衫,擦干裤子
- 叠衬衫,(从架子上拿外套)
- 把衬衫放回架子上,叠裤子,(洗外套)
-
把裤子放回架子上,(晾干外套)
- (熨烫外套)
- (把外套放回架子上)
这是流水线。 对不相关的活动进行排序,以便它们同时使用不同的组件。通过同时保持尽可能多的不同组件处于活动状态,您可以最大限度地提高效率并加快执行时间,在这种情况下,将 16 个“周期”减少到 9 个,加速超过 40%。
现在,这家小干洗店开始赚更多的钱,因为他们可以工作得更快,所以店主额外买了一台洗衣机、烘干机、熨衣板、折叠台,甚至还雇了一个服务员。现在事情变得更快了,而不是上面的,你有:
- 从架子上拿衬衫,从架子上拿裤子
- 洗衬衫,洗裤子,(从架子上拿外套)
- 擦干衬衫,擦干裤子,(洗外套)
- 熨烫衬衫,叠裤子,(晾干外套)
- 叠衬衫,把裤子放回架子上,(熨烫外套)
- 把衬衫放回架子上,(把外套放回架子上)
这是超标量设计。 多个子组件能够同时执行相同任务,但由处理器决定如何执行。在这种情况下,它导致了近 50% 的速度提升(在 18 个“周期”中,新架构可以运行该“程序”的 3 次迭代,而之前的架构只能运行 2 次)。
较旧的处理器(例如 386 或 486)是简单的标量处理器,它们一次执行一条指令,其顺序与接收指令的顺序完全相同。自 PowerPC/Pentium 以来的现代消费类处理器是流水线和超标量的。 Core2 CPU 能够运行为 486 编译的相同代码,同时仍然利用指令级并行性,因为它包含自己的内部逻辑,可以分析机器代码并确定如何重新排序和运行它(可以并行运行的,什么不能,等等。)这就是超标量设计的精髓,也是它如此实用的原因。
相比之下,向量并行处理器一次对多条数据(向量)执行操作。因此,向量处理器不只是将 x 和 y 相加,而是将 x0,x1,x2 添加到 y0,y1,y2(产生 z0,z1,z2)。这种设计的问题在于它与处理器的特定并行度紧密耦合。如果您在矢量处理器上运行标量代码(假设可以),您将看不到矢量并行化的优势,因为它需要明确使用,同样如果您想利用具有更多并行处理单元的更新矢量处理器(例如能够添加 12 个数字的向量,而不仅仅是 3) 你需要重新编译你的代码。矢量处理器设计在最老一代的超级计算机中很流行,因为它们易于设计,并且在科学和工程中存在大量自然并行性问题。
超标量处理器也可以执行推测执行。与其让处理单元空闲并在分支处理器之前等待代码路径完成执行,不如做出最佳猜测并在先前代码完成处理之前开始执行经过分支的代码。当先前代码的执行赶上分支点时,处理器可以将实际分支与分支猜测进行比较,如果猜测正确则继续(已经远远领先于等待的位置),或者它可以使推测执行的结果无效并为正确的分支运行代码。