一、GPU计算概述:为什么需要GPU?

大家好,我是这门课的主讲工程师。今天咱们聊聊最基础的问题——为什么我们需要GPU?

说实话,我刚入行那会儿也觉得CPU挺够用的。直到有一次做图像处理项目,一张4K图片的滤波运算,CPU跑了整整3秒。我当时就想:这要是做视频流处理,每秒30帧,岂不是要卡到天荒地老?

嗯,这就是GPU登场的理由。

1.1 CPU与GPU的架构差异

先看一张对比表,你就能明白两者本质区别:

对比维度 CPU GPU
设计目标 低延迟、串行处理 高吞吐、并行处理
核心数量 4-16个(高性能) 数千个
缓存结构 大容量多级缓存 小缓存,依赖显存
控制单元 复杂(分支预测、乱序执行) 简单(SIMT模式)
适用场景 操作系统、逻辑控制 矩阵运算、图像渲染

说白了,CPU像个全能冠军——什么活都能干,但一次只能干几件。GPU像个流水线工人——只会干一件事,但可以同时干成千上万件。

核心观点:CPU擅长「等待」——等内存、等硬盘、等用户输入。GPU擅长「干活」——只要数据喂得够快,它能一直算下去。

1.2 为什么CPU搞不定大规模并行?

你想想看,CPU芯片上很大一部分面积被控制逻辑和缓存占用了。我拆过几颗CPU的die照片,真正做算术的ALU单元只占很小一块。

为什么会这样?因为CPU要处理各种 unpredictable 的情况——分支跳转、异常处理、多任务切换。这些都需要复杂的控制电路。

而GPU呢?它假设所有线程都在做同样的事。你让1000个线程同时做A+B,它们就老老实实做A+B。不需要分支预测,不需要乱序执行。

我的经验:有一次我优化一个物理模拟程序,CPU版本用了OpenMP并行,加速比只有4倍(8核)。改成CUDA后,直接跑了200倍加速。不是CPU不行,是场景不对。

1.3 GPU的适用场景

不是所有程序都适合GPU。我见过有人非要用GPU跑数据库查询,结果比CPU还慢。这里列几个典型的「GPU友好」场景:

  • 矩阵运算:线性代数、神经网络训练
  • 图像处理:滤波、卷积、特征提取
  • 科学计算:分子动力学、流体模拟
  • 信号处理:FFT、卷积编码
  • 数据并行:对大量独立数据做相同操作

判断标准很简单:数据之间有没有依赖?如果每个数据点的计算可以独立进行,GPU就是好选择。如果必须等前一步结果才能算下一步,那还是CPU更合适。

避坑指南:我曾经接手过一个项目,对方把整个程序都扔到GPU上跑,包括文件读写和网络通信。结果CPU在等GPU,GPU在等数据,两边都闲着。记住:GPU只负责计算,I/O和逻辑控制留给CPU。

1.4 一个简单的例子

假设我们要对100万个浮点数做平方运算。CPU代码大概这样:

// CPU版本
for (int i = 0; i < 1000000; i++) {
    result[i] = data[i] * data[i];
}

GPU版本呢?每个线程只算一个数:

// GPU版本(CUDA)
__global__ void square(float* data, float* result) {
    int i = threadIdx.x + blockIdx.x * blockDim.x;
    if (i < 1000000) {
        result[i] = data[i] * data[i];
    }
}

你看,GPU版本多了线程索引的计算,但换来的是成千上万个线程同时执行。在我的GTX 1080上,CPU跑这个循环大概要3毫秒,GPU只要0.02毫秒——150倍的差距

1.5 什么时候不该用GPU?

我也得说点大实话。以下情况GPU反而帮倒忙:

  • 数据量太小:少于1000个元素,CPU更快
  • 分支密集:每个线程走不同路径,GPU效率暴跌
  • 频繁同步:线程之间需要不断交换数据
  • I/O密集型:大部分时间在读写文件

我记得有个学生问我:「老师,我写了个冒泡排序用GPU跑,为什么比CPU慢?」我笑了笑——冒泡排序本身就是串行算法,每一步都依赖上一步结果。这种场景,CPU才是王道。

小结

这一章我们聊了:

  • CPU和GPU的架构差异——一个精而少,一个多而简
  • GPU的适用场景——数据并行、计算密集
  • 什么时候不该用GPU——数据少、分支多、依赖强

下一章,我们会深入CUDA编程模型,看看怎么真正让GPU跑起来。到时候我会分享一些我踩过的坑——嗯,保证让你少走弯路。