为什么GPU如此强大,CPU依然不可或缺?

为什么GPU如此强大,CPU依然不可或缺?

最近,一段2009年的老视频在推特上重新火了起来,旨在向观众直观展示CPU与GPU之间的差异。

视频的内容可以在这里观看,时长90秒:
视频链接

视频的核心思想是:CPU和GPU进行了一场绘画对决。它们连接到一个喷射彩弹的机器上,CPU花费了30秒钟画出一个简单的笑脸。

而GPU则在瞬间画出了蒙娜丽莎。

从这个视频中得出的一个结论是:CPU很慢,而GPU很快。虽然这有一定的道理,但实际上,背后还有更多的细节和复杂性。

TFLOPS:衡量处理器性能的标准

当我们说GPU比CPU强大时,通常指的是TFLOPS(每秒万亿次浮点运算)的概念。TFLOPS用来衡量一个处理器每秒能进行多少次数学运算。例如,Nvidia的A100 GPU可以执行9.7 TFLOPS(即每秒97亿次操作),而Intel最近的24核处理器只能达到0.33 TFLOPS。这意味着,即使是中端GPU,其性能也至少是最强CPU的30倍。

那么,为什么我MacBook里的Apple M3芯片既包含了CPU又包含了GPU呢?难道我们不能完全抛弃这些”缓慢”的CPU吗?

程序类型的差异

我们可以将程序分为两种类型:顺序程序和并行程序。

顺序程序

顺序程序是指所有指令必须一条接一条执行的程序。以下是一个简单的例子:

1
2
3
4
5
6
7
8
def sequential_calculation():
a = 0
b = 1

for _ in range(100):
a, b = b, a + b

return b

在这个例子中,计算Fibonacci数列时,每一步都依赖于前两步的结果。如果你手工计算,你不能让朋友从第51步开始计算,因为他需要第49步和第50步的结果才能计算第51步。每一步都依赖于前面几步的计算。

并行程序

与顺序程序不同,并行程序中的多条指令可以同时执行,因为它们之间没有依赖关系。举个例子:

1
2
3
4
5
6
7
8
def parallel_multiply():
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
results = []

for n in numbers:
results.append(n * 2)

return results

在这个例子中,我们对10个数进行了独立的乘法运算。这里的关键是顺序不重要。如果你和朋友分担工作,你可以让他负责计算奇数,自己负责偶数,两个人可以同时工作,得到正确的结果。

一个虚假的二分法

现实中,顺序与并行的划分并不是那么绝对。大多数大型现实应用程序都包含了顺序和并行代码的混合。事实上,每个程序都会有一部分指令是可以并行化的。

举个例子,假设我们有一个程序需要进行20次计算,其中前10次是Fibonacci数列计算,必须顺序执行,而后10次可以并行进行。我们就可以说,这个程序的“并行化程度是50%”,因为其中一半的指令是可以独立完成的。来看这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def half_parallelizeable():
# Part 1: 顺序的Fibonacci计算
a, b = 0, 1
fibonacci_list = [a, b]
for _ in range(8): # 计算另外8个数
a, b = b, a + b
fibonacci_list.append(b)

# Part 2: 每一步都可以独立执行
parallel_results = []
for n in fibonacci_list:
parallel_results.append(n * 2)

return fibonacci_list, parallel_results

前半部分的计算必须顺序执行(因为每个Fibonacci数都依赖前两个数),但一旦生成了完整的Fibonacci数列,后续的乘以2操作就可以并行化。

不同程序需要不同的处理器

大体来说,CPU适合处理顺序程序,而GPU则擅长并行程序。这是因为CPU和GPU在设计上有根本的差异。

CPU通常有较少的大核心(例如,Apple M3有8个CPU核心),而GPU则拥有大量的小核心(例如,Nvidia的H100 GPU有成千上万的核心)。

这就是为什么GPU特别擅长执行高度并行的任务——它们有成千上万个简单的核心,可以同时在不同的数据上执行相同的操作。

以视频游戏图形渲染为例,渲染需要大量的重复计算。可以把游戏画面看作一个巨大的像素矩阵。当你突然让角色向右转时,屏幕上的所有像素都需要重新计算新的颜色值。幸运的是,屏幕上方的像素和下方的像素之间是独立的,因此这些计算可以分配给GPU的成千上万个核心。这就是为什么GPU在游戏中如此重要。

CPU擅长处理随机事件

虽然GPU在高度并行的任务(例如,乘法运算)上比CPU快得多,但它们在复杂的顺序处理和决策制定方面不如CPU。

可以把CPU核心比作餐厅厨房里的主厨,这位主厨可以:

  • 在VIP客人到来并提出特殊饮食要求时,立即调整菜肴计划
  • 在制作精细酱汁和检查烤制蔬菜之间灵活切换
  • 遇到停电等突发状况时,重新组织整个厨房流程
  • 协调多个菜肴的制作,使它们都能在恰到好处的时刻准时上桌
  • 在处理多道菜肴的同时保持食物质量

相比之下,GPU核心更像是厨房里的一百个切菜工,他们擅长重复性的任务——可以在2秒钟内切完一个洋葱,但无法有效管理整个厨房。如果你让GPU来应对餐厅高峰期不断变化的需求,它可能会感到力不从心。

这就是为什么CPU在运行操作系统时如此关键。现代计算机需要应对源源不断的不可预测事件:应用程序的启动和停止、网络连接的断开、文件的访问、用户在屏幕上的随机点击等。CPU在处理这些事件时非常高效,它能够保证系统的流畅性和响应能力。CPU可以在毫秒之间从帮助Chrome浏览器渲染网页切换到处理Zoom视频通话,再到接入新的USB设备,同时确保所有应用程序得到适当的资源分配。

因此,虽然GPU在并行计算方面表现出色,CPU仍然是处理复杂逻辑和应对变化环境的核心。

现代芯片(如Apple的M3)将两者结合,既保留了CPU的灵活性,又拥有GPU强大的计算能力。事实上,视频中的绘画场景更准确的版本应该是:CPU负责管理图像的下载和内存分配,然后再将渲染任务交给GPU来快速生成像素。