目录
1.同构和异构的区别
2.为什么要出现异构,同构不行吗?
3.异构架构
4.异构应用
5.NVIDIA
6.范例
7.CUDA:一种异构计算平台
8.CUDA应用
9.实战—第一个程序hello world
10. CUDA C 难吗?—— 难点不在语法,而在硬件思维
总结
1.同构和异构的区别
同构与异构的核心区别在于:组成系统的各个计算单元,在架构上是不是一样的。
cpu和gpu就是异构,两个芯片都不一样
-
同构:指系统中所有处理器都是同一种架构。比如一个服务器集群里全是 x86 架构的 Intel CPU,或者一个早期系统中只有几颗型号完全相同的 CPU 协同工作。
-
异构:指系统中集成了多种不同架构的处理器。最常见的就是 x86 CPU + NVIDIA GPU。CPU 架构重逻辑控制与低延迟,GPU 架构重数据并行与高吞吐量,它们架构设计哲学完全不同,因此是“异构”的。
2.为什么要出现异构,同构不行吗?
因为同构架构无法在所有类型的任务上都做到极致高效。
-
同构的局限:让 CPU 去做大规模的并行图形或矩阵运算,可行,但是慢,效率低
-
异构的优势:通过 PCIe 总线把 CPU 和 GPU 连起来,让 CPU 负责指挥、处理逻辑和串行部分,把海量的并行计算任务“外包”给 GPU。这就是 “CPU + GPU”的异构计算模式,超算中心最主流的架构。
3.异构架构

GPU插在主板的PCIe卡口上,运行程序的时候,CPU像是一个控制者,指挥GPU完成工作后进行汇总,和下一步工作安排,所以CPU我们可以把它看做一个指挥者,主机端,host,而完成大量计算的GPU是我们的计算设备,device。
- 左图:一个四核CPU一般有四个ALU,ALU是完成逻辑计算的核心,也是我们平时说四核八核的核,控制单元,缓存也在片上,DRAM是内存,一般不在片上,CPU通过总线访问内存。
- 右图:GPU,绿色小方块是ALU,我们注意红色框内的部分SM,这一组ALU公用一个Control单元和Cache,这个部分相当于一个完整的多核CPU,但是不同的是ALU多了,control部分变小,可见计算能力提升了,控制能力减弱了,所以对于控制(逻辑)复杂的程序,一个GPU的SM是没办法和CPU比较的,但是对了逻辑简单,数据量大的任务,GPU更高效,并且,注意,一个GPU有好多个SM,而且越来越多。
补充知识
PCIe总线,全称是Peripheral Component Interconnect Express(高速外设组件互连)。
| GPU 内部显存带宽 | 极高(如 1TB/s 级别) | 从北京到上海,铺了1000条车道的高速路 |
| PCIe 总线带宽 | 相对低(如 64GB/s 级别) | 同一条路,但车道骤减到只有60条 |
| CPU 内存带宽 | 中等 | 同一条路,有几百条车道 |
不难想到瓶颈就在PCle总线上,会拖垮GPU的计算速度,
尽量减少 CPU 和 GPU 之间通过 PCIe 的数据搬运次数。尽可能一次性把数据搬到显存,让 GPU 反复计算,算完再把最终结果传回。
4.异构应用
一个异构应用包含两种以上架构,所以代码也包括不止一部分:
- 主机代码
- 设备代码
主机代码在主机端运行,被编译成主机架构的机器码,设备端的在设备上执行,被编译成设备架构的机器码,所以主机端的机器码和设备端的机器码是隔离的,自己执行自己的,没办法交换执行。 主机端代码主要是控制设备,完成数据传输等控制类工作,设备端主要的任务就是计算。 因为当没有GPU的时候CPU也能完成这些计算,只是速度会慢很多,所以可以把GPU看成CPU的一个加速设备。
5.NVIDIA
计算平台(不是架构,底层架构一样),底层有些显卡的硬件是不同的,比如GeForce计算平台就少了一些双精度浮点单元的硬件,因为没必要,而且会增加成本
| GeForce | 消费级游戏/入门AI | 民用跑车 | 个人电脑、笔记本 |
| Tesla | 数据中心/大规模AI训练 | 专业赛车 | 云服务器、科研中心 |
| Quadro | 专业设计/影视特效 | 工程抢险车 | 设计师工作站、影视公司 |
| Tegra | 低功耗嵌入式智能 | 微型无人机引擎 | 机器人、自动驾驶汽车 |
衡量GPU计算能力的主要靠下面两种容量特征:
- CUDA核心数量(越多越好)
- 内存大小(越大越好)
相应的也有计算能力的性能指标:
- 峰值计算能力
- 内存带宽
架构:这里才是架构的不同,注意Tesla和上面的计算平台不一样
这就好比,底盘是不一样,计算平台就是底盘一样,但是有的可以造燃油汽车,有的造电动车,这里的架构不一样就是底盘不一样
现在已经出现第8代了
6.范例

尺有所短,寸有所长
-
CPU:适合低并行、逻辑复杂的任务。
-
GPU:适合高并行、逻辑简单的大数据计算。

-
串行部分:这部分必须由 CPU 来执行。比如复杂的控制逻辑、分支判断、文件读写、任务调度等。这部分代码就像建筑的总设计师,负责规划和指挥。
-
并行部分:这部分可以交给 GPU 来执行。比如对海量数据做相同的数学运算(矩阵乘法、图像滤镜等)。这部分代码就像一个由成千上万个工人组成的施工队,每人只干一件简单的活,但一起干就很快
整个“异构计算”的精髓就在这里:CPU 负责指挥和串行工作,GPU 负责处理被调派过来的海量并行任务。它们通过 PCIe 总线连接和传递数据。
cpu线程和gpu线程有何区别
-
CPU 线程是“重量级”的:操作系统切换线程代价很高,像专家开会,每次离场入场都很麻烦。所以 CPU 设计目标是让少数几个线程跑得极快,减少延迟。
-
GPU 线程是“轻量级”的:切换基本无开销,像几千个工人,随时可以有工人被换下休息,另一个工人立刻顶上。所以 GPU 的设计目标是让海量线程同时工作,最大化吞吐量。
别指望用 CPU 去干 GPU 擅长的大规模并行计算,也别用 GPU 去处理复杂的逻辑控制。一个高性能的程序,必然是把任务正确分解,让CPU做好指挥,让GPU做好计算的异构协作。
7.CUDA:一种异构计算平台
CUDA平台不是单单指软件或者硬件,而是建立在Nvidia GPU上的一整套平台,并扩展出多语言支持

GPU计算的技术层级结构,从下到上分为三个主要层次,解释了如何构建和运行GPU计算应用:
1. 底层:编程语言(Programming Languages)
这是开发GPU程序的基础,支持多种语言:
-
传统语言:C、C++、Fortran(适合高性能计算)
-
高级语言:Python(简化开发,常结合库使用)
-
指令扩展:DirectCompute、Directives(如OpenACC,通过编译器指令简化并行编程)
这些语言为开发者提供了编写GPU代码的“语法基础”。
2. 中间层:库和中间件(Libraries and Middleware)
这一层提供了预封装的工具和接口,让开发者无需从零开始编写底层GPU代码,可直接调用现成的功能:
-
数学/科学计算库:CUFFT(快速傅里叶变换)、CUBLAS(线性代数)、CUPARSE(稀疏矩阵)等
-
通用计算库:Thrust(类似C++ STL的并行算法库)、NPP(NVIDIA性能原语)
-
可视化/物理引擎:PhysX(物理模拟)、OptiX(光线追踪)、iray(渲染)
-
科学计算软件:MATLAB、Mathematica(集成GPU加速功能)
这些库封装了复杂的GPU操作(如内存管理、并行调度),让开发者能更高效地实现特定功能。
3. 顶层:GPU计算应用(GPU Computing Applications)
这是最终面向用户的应用层,利用底层语言和中间件库实现具体功能,例如:
-
科学计算(气候模拟、分子动力学)
-
机器学习/深度学习(训练模型)
-
图形渲染(电影特效、游戏)
-
数据分析(大规模数据处理)
CUDA C是标准ANSI C的扩展,通过新增语法和关键字,让开发者能编写设备端代码(在GPU上运行的代码);同时,CUDA库提供了大量API,帮助开发者操作GPU硬件完成计算(如内存分配、内核启动、数据传输等)。
对于API也有两种不同的层次,一种相对交高层,一种相对底层。
- CUDA驱动API
- CUDA运行时API

驱动API是低级的API,使用相对困难
运行时API是高级API使用简单,其实现基于驱动API。 这两种API是互斥的,也就是你只能用一个,两者之间的函数不可以混合调用,只能用其中的一个库。你不能用运行时 API(如 cudaMalloc)分配一块内存,然后试图用驱动 API(如 cuMemFree)去释放它。
8.CUDA应用

一个CUDA应用通常可以分解为两部分,
- CPU 主机端代码
- GPU 设备端代码
CUDA nvcc编译器会自动分离你代码里面的不同部分,如图中主机代码用C写成,使用本地的C语言编译器编译,设备端代码,也就是核函数,用CUDA C编写,通过nvcc编译,链接阶段,在内核程序调用或者明显的GPU设备操作时,添加运行时库。
nvcc 是从LLVM开源编译系统为基础开发的。NVCC 和熟悉的 GCC 最大的不同,就是它能自动分离代码,然后调用不同的后端编译器,生成两种完全不同的机器码。


CUDA工具箱提供编译器,数学库,调试优化等工具,当然CUDA的文档是相当完善的,可以去查阅,当然在我们基本了解基础结构的情况下,直接上来看文档会变得机械化。
CUDA程序是一个进程。CPU执行编译器翻译好的x86机器码。当需要GPU时,CPU通过CUDA运行时库,把任务打包成命令,提交到命令队列,然后立刻返回继续执行。GPU驱动在后台把命令发给GPU,GPU开始执行。此时CPU和GPU各自在物理上并行工作。需要同步时,必须显式调用同步函数。
9.实战—第一个程序hello world
这里采用windows下的wsl虚拟机+vscode(大家可以自行搜索相关文章进行下载配置好)
#include <stdio.h>
__global__ void hello(void){
printf("hello world\\n");
}
int main(){
printf("正在执行cpu端代码");
hello<<<1,10>>>();
cudaDeviceReset();
return 0;
}
-
__global__:这是 CUDA 的关键字,告诉 NVCC 编译器:这个函数是一个“核函数”(Kernel)。
-
它由 CPU 调用,但实际在 GPU 上执行。
-
它的返回类型必须是 void。
-
-
hello_world(void):这就是核函数本身。它被 GPU 上的每个线程各自执行一次。所以,如果你启动了 10 个线程,GPU 就会打印 10 次 "GPU: Hello world!\\n"。
-
int main就是cpu代码,__global__就是gpu代码
-
hello_world<<<1,10>>>();:这是 CUDA 特有的核函数启动语法,是整个程序的核心。
-
<<<1,10>>> 叫做执行配置,它决定了用多少线程来跑这个核函数。
-
第一个数字 1:表示启动 1 个线程块(Block)。
-
第二个数字 10:表示每个线程块里有 10 个线程(Thread)。
-
所以,总共会启动 1 × 10 = 10 个线程,它们同时在 GPU 上执行 hello_world 核函数,各自打印一句话。
-
-
cudaDeviceReset():这是一个显式同步和清理函数。
-
为什么必须有它? 因为 CPU 调用核函数(<<<>>>)后,是异步的:CPU 只负责下命令,然后立刻继续执行下一行代码,不会等 GPU 干完活。
-
如果没有这一行,main 函数可能瞬间结束,整个进程退出,此时 GPU 可能还没来得及把 "GPU: Hello world!\\n" 打印到终端。cudaDeviceReset() 会强制 CPU 等待 GPU 所有任务完成并清理资源,确保你能看到 GPU 的输出。
-

运行结果跟预期一样
接下来我们把同步函数注释掉,显然cpu会直接退出,gpu还未来得及打印到屏幕,所以后面没有打印10句hello world


| 函数声明 | 无特殊标记 | 必须加 __global__ |
| 返回值类型 | 任意类型 | 只能 void |
| 参数 | 任意类型 | 任意类型,但通常是指向显存的指针 |
| 谁调用 | CPU | CPU(用 <<<>>> 语法) |
| 在哪里执行 | CPU 上 | GPU 上,每个线程都执行一遍 |
| 执行方式 | 调用一次,执行一次 | 调用一次,成千上万个线程同时执行 |
一般CUDA程序分成下面这些步骤:
上面的hello world只到第三步,没有内存交换。
10. CUDA C 难吗?—— 难点不在语法,而在硬件思维
CUDA C 的语法本身不难,难的是你必须理解 GPU 的硬件架构,才能写出高效的代码。
为什么理解机器结构至关重要? 因为 GPU 是为大规模并行计算设计的,它的性能极度依赖于你如何组织数据和线程。
决定性能的关键因素:数据局部性
-
空间局部性:当你访问一个数据时,它附近的数据很可能马上也会被访问。GPU 的显存系统喜欢“连续”的访问,比如一次读一片连续地址,而不是东读一个西读一个。
-
时间局部性:一个刚被用过的数据,很可能过一会儿又会被用到。这就是“缓存”存在的意义,把常用的数据放在离计算核心更近的高速存储里。
写代码的指导意义是:你要尽量让线程访问连续的内存地址,并让相同的数据被多次使用,而不是每次都去慢速的显存里重新拿。
CUDA抽象了硬件实现:
CUDA 编程最核心的学习对象就是两个模型,它们直接影响 GPU 的执行效率:
-
内存层次结构 GPU 的内存不是平坦的一大块,而是像金字塔一样分层:离计算核心越近的(寄存器、共享内存)速度越快但容量越小,越远的(全局显存)速度越慢但容量越大。你的任务就是手动管理数据在金字塔中的流动,让计算核心尽量用上最快的那层内存。
-
线程层次结构 你在写核函数时,看似只写了一小段串行代码,但实际上,这段代码会被成千上万个线程同时执行。CUDA 提供了一个层次化的线程组织模型(网格 → 线程块 → 线程),这种组织方式直接决定了这些线程在 GPU 硬件上是如何被调度和执行的。
这两个模型是 CUDA 高性能编程的“任督二脉”,后面大部分的学习都围绕着它们展开。
我们能用到的工具相当丰富,NVIDIA为我们提供了:
-
Nvidia Nsight:集成化的性能分析和调试环境,可以看到你的代码在 GPU 上是怎么跑的。
-
CUDA-GDB:命令行调试器,可以像调试 CPU 程序一样调试 GPU 核函数。
-
性能分析可视化工具:帮你一眼看出瓶颈在哪。
-
CUDA-MEMCHECK:专门检查内存访问错误(越界、泄漏等)的工具。
-
GPU 设备管理工具:比如 nvidia-smi,监控 GPU 状态。
总结
学习好线程组层次、内存层次、障碍同步这些概念,就能高效地驾驭 GPU,而不需要去死记硬背每代硬件的具体物理细节。这些抽象是 CUDA 为你提供的稳定编程接口。
本文主要理解了大致框架,即将踏入并行编程的世界

