一、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跑起来。到时候我会分享一些我踩过的坑——嗯,保证让你少走弯路。