CUDA Thread / Block / Warp 完整区别
- Thread(线程):GPU最小执行单元,对应一条标量指令;
- Block(线程块):软件逻辑分组,CPU调用Kernel时手动划分,块内共享Shared Memory;
- Warp(束) :硬件物理调度单元,由SM流式多处理器硬件自动分组,固定32个Thread为1个Warp。
一、逐个定义
1. Thread 线程
GPU最细粒度计算单元,执行内核函数 __global__ 里的一次迭代。
- 程序员通过
threadIdx.x、threadIdx.y、threadIdx.z获取线程在所属 Block 内的三维索引,这是线程在块内的唯一标识。 - 单个线程执行串行指令,本身没有并行调度能力,必须打包成 Warp 由 SM(流式多处理器)统一调度。
- 每个线程拥有独立的程序计数器(PC)和寄存器文件,可以独立执行指令流,这是 SIMT(单指令多线程)架构的基础。
- 线程是数据并行的最小载体:在典型的 CUDA 内核中,每个线程处理一个数据元素(如数组中的一个像素、矩阵中的一个元素)。
- 线程之间通过**全局内存(Global Memory)**进行通信,但访问延迟高;高效协作需依赖 Block 内的共享内存或 Warp 内的寄存器通信。
2. Thread Block 线程块(逻辑层,软件抽象)
- 程序员在调用
kernel<<<gridDim, blockDim>>>时自定义划分,比如dim3 block(256); - 一个Block内最多 1024个线程(硬件硬限制);
- 核心特权:同一个Block内部所有线程可以访问块内共享内存
__shared__,可以使用__syncthreads()做块内线程同步; - Block之间完全独立、无法直接通信、没有同步机制,由GPU调度器分发到不同SM执行。
Block 内部会被硬件自动切分成若干个Warp。
例:Block=256线程 → 256/32 = 8个Warp。
3. Warp 线程束(硬件调度最小单元,硬件抽象)
- NVIDIA GPU SM(Streaming Multiprocessor)固定32个连续线程捆绑为1个Warp,这是硬件天生规则,不可改;
- SM以Warp为单位做指令发射、流水线调度、寄存器分配;
- 一个Warp内32条线程默认锁步执行(SIMT):同一周期执行同一条指令;
- 一个Block的线程按连续顺序打包进Warp,最后不足32的部分填充为无效线程。
二、核心维度对比表
| 维度 | Thread Block(线程块) | Warp(线程束) |
|---|---|---|
| 层级属性 | 软件逻辑分组,程序员定义 | 硬件物理调度分组,GPU自动拆分 |
| 大小规则 | 1~1024 任意设置,常用64/128/256 | 固定32线程,NVIDIA架构不可修改 |
| 内存权限 | 拥有 __shared__ 共享内存,块内同步 |
无独立共享内存,隶属于某个Block |
| 同步能力 | 块内可用 __syncthreads() 强同步 |
无法手动同步,硬件SIMT锁步执行 |
| 分裂代价 | Block之间无分支影响 | 分支会产生 Warp Divergence(束分化),性能暴跌 |
| 可见性 | Grid下多层Block互相隔离 | 仅SM内部调度单元,程序员不可直接操作 |
三、最关键性能痛点:Warp Divergence 束分化
这是理解Warp最重要的知识点:
1个Warp 32个线程如果进入不同分支(if/else):
- 硬件会串行执行所有分支路径;
- 走if的16条线程执行时,另外16条闲置;再执行else,前面16条闲置;
等效算力直接折半甚至更低。
Block 不会产生这个问题,Block只是容器。
优化方案:保证同一个Warp内线程分支走向一致(按32对齐判断条件)。
四、层级嵌套完整结构
Grid(整个Kernel网格)
├─ Block 0(逻辑块,256线程)
│ ├─ Warp0(线程0~31)
│ ├─ Warp1(线程32~63)
│ └─ ... 共8个Warp由SM硬件调度
├─ Block 1
└─ Block N
五、极简总结
- Block 是人定的逻辑组:用来分配共享内存、做块内同步,上限1024线程;
- Warp 是GPU硬件定的执行组:强制32线程一组,SM最小调度发射单位;
- Block 内部线程由硬件自动拆成多个Warp,Warp内分支造成束分化是CUDA最经典性能坑;
- AI编译(IREE/MLIR→NVPTX)做GPU向量化时,本质就是对齐Warp 32粒度做访存合并与指令打包。