面试官问这个问题的时候,很多 Java 程序员第一反应是:“GPU 不就是显卡吗?跑游戏的?”
这个回答基本凉一半。
我以前排查线上性能问题时,经常会遇到类似的误区。大家看到 CPU 飙高,就觉得“是不是代码死循环”;看到机器有 GPU,就觉得“是不是换个 GPU 就快了”。
其实 CPU 和 GPU 从设计目标开始就不是一类东西。
CPU 更像一个经验丰富的项目经理。
事情不多的时候,它什么都能干:安排任务、处理异常、判断分支、管理资源。
GPU 更像一万个流水线工人。
每个人能力没 CPU 强,但是任务规则简单,可以同时干大量重复工作。
这也是为什么挖矿、大模型训练都会大量使用 GPU。
先看 CPU。
CPU 的核心设计目标是低延迟、高通用性。
比如 Java 程序执行下面这段代码:
public class OrderCalculator {
public int calculatePrice(Order order) {
if (order.getVip()) {
return order.getAmount() * 8 / 10;
}
if (order.getCoupon() != null) {
return order.getAmount() - order.getCoupon();
}
return order.getAmount();
}
}
这里面大量都是判断。
VIP 怎么处理?
有没有优惠券?
不同用户走不同逻辑。
CPU 很擅长这种事情。
因为 CPU 里面有复杂的控制单元,可以预测分支,可以调整指令执行顺序,还有很大的缓存。
简单说:
CPU 擅长“少量复杂任务”。
比如:
- 操作系统调度
- Java 服务请求处理
- 数据库事务
- 网络 IO
- 编译代码
而 GPU 设计的时候,想的是另外一个问题:
如果我要同时处理一百万个类似计算怎么办?
比如图片渲染。
一张图片有 4000 万个像素,每个像素颜色计算方式基本一样。
CPU 一个个处理:
像素1 -> 计算
像素2 -> 计算
像素3 -> 计算
...
效率很低。
GPU 的思路:
线程1 处理像素1
线程2 处理像素2
线程3 处理像素3
...
线程40000000 处理像素40000000
大家同时算。
所以 GPU 的核心优势就是并行计算。
我举个 Java 里面更容易理解的例子。
假设现在有 100 万用户,需要计算积分。
CPU 写法:
public void calculateScore(List<User> users) {
for (User user : users) {
int score = user.getOrderCount() * 10
+ user.getLevel() * 100;
user.setScore(score);
}
}
这个逻辑没有问题。
但是它本质是一条流水线:
用户1 计算
用户2 计算
用户3 计算
...
用户1000000 计算
如果这个计算非常简单,CPU 一个线程也能跑。
但如果每个用户的数据计算量很大,比如模型推理、矩阵计算,这种方式就慢了。
GPU 更适合:
用户1 计算
用户2 计算
用户3 计算
同时进行
因为这些计算之间没有依赖。
那为什么挖矿喜欢 GPU?
以前很多人挖矿的时候,本质是在不停计算哈希。
比如:
hash(block + nonce)
不停尝试不同 nonce:
nonce=1
nonce=2
nonce=3
nonce=4
...
每一次计算之间没有关系。
找到满足条件的结果就结束。
这种任务特别适合 GPU。
因为:
如果用 CPU:
CPU 核心1:
计算 hash1
CPU 核心2:
计算 hash2
CPU 核心3:
计算 hash3
几十个核心已经顶天。
但是 GPU:
CUDA Core 1:
hash1
CUDA Core 2:
hash2
CUDA Core 3:
hash3
...
几千个核心一起跑
吞吐量直接拉开。
大模型为什么也用 GPU?
这个问题滴滴面试大概率会继续追问。
因为大模型训练里面大量都是矩阵计算。
比如神经网络里面:
Y = X * W + B
本质就是矩阵乘法。
假设:
X:
10000 × 10000
W:
10000 × 10000
计算量非常巨大。
但是每个元素计算方式类似。
GPU 非常喜欢这种任务。
简单写个矩阵计算:
public class MatrixMultiply {
public static double[][] multiply(
double[][] a,
double[][] b) {
int n = a.length;
double[][] result = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
double sum = 0;
for (int k = 0; k < n; k++) {
sum += a[i][k] * b[k][j];
}
result[i][j] = sum;
}
}
return result;
}
}
这个代码 Java 程序员一眼能看懂。
但是问题来了:
如果 n=10000。
这里面的循环次数:
10000 * 10000 * 10000
就是万亿级计算。
CPU 慢在哪里?
不是 CPU 算不了。
而是它一次处理有限数量任务。
GPU 会把矩阵拆开:
线程1 算 result[0][0]
线程2 算 result[0][1]
线程3 算 result[0][2]
...
大量线程同时计算。
不过 GPU 也不是万能的。
我线上遇到过一些团队,看到 AI 火,就想着:
“服务器换 GPU,是不是接口马上提升?”
这里容易踩坑。
如果你的业务:
public User queryUser(Long id) {
User user = userDao.selectById(id);
return user;
}
主要瓶颈是:
- MySQL 查询慢
- Redis 命中率低
- 网络延迟
- 锁竞争
换 GPU 没任何意义。
GPU 不会帮你优化 SQL。
不会减少 TCP 延迟。
不会解决 Java 线程池配置问题。
CPU 和 GPU 的区别,可以从几个角度理解。
指令处理:
CPU:
少量核心
复杂逻辑
强控制能力
GPU:
大量核心
简单逻辑
强并行能力
任务类型:
CPU:
if else
事务
接口调用
系统调度
GPU:
矩阵计算
图像处理
密码计算
深度学习
内存设计:
CPU 更依赖缓存。
比如:
L1 Cache
L2 Cache
L3 Cache
内存
因为它希望快速处理各种随机任务。
GPU 更关注数据吞吐。
大量数据搬进去,然后批量计算。
所以面试的时候,如果让我回答,我一般不会说:
“GPU 比 CPU 快。”
这个说法太粗。
准确说:
GPU 在高度并行、计算规则固定的数据处理场景下,比 CPU 有更高吞吐能力。
CPU 负责复杂控制。
GPU 负责大规模并行计算。
现在很多 AI 服务器为什么是:
CPU + GPU
而不是:
CPU 或 GPU 二选一
原因也很简单。
CPU 管系统。
比如:
GPU 管计算。
比如:
就像 Java 服务里面:
CPU 是负责接收订单、校验参数、调用库存。
GPU 是负责一次计算几百万用户画像。
两者不是替代关系。
一个负责把事情安排明白。
一个负责把重复计算做到极致。