news 2026/6/10 9:51:18

线程层次结构:Thread, Block, Grid

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线程层次结构:Thread, Block, Grid

CUDA 编程模型采用了一个三层的线程层次结构,旨在映射到 GPU 硬件的多级架构,实现最大的并行性和数据局部性。

1. 线程 (Thread)

线程是 CUDA 并行计算的基本执行单元

  • 定义:在 Kernel 函数中,每个并行计算的实例就是一个线程。例如,在向量加法中,一个线程负责计算C[i]=A[i]+B[i]C[i] = A[i] + B[i]C[i]=A[i]+B[i]

  • 标识:每个线程都有一个内置的唯一标识符threadIdx

    • threadIdx.xthreadIdx.ythreadIdx.z:线程在当前线程块内的坐标。
  • 执行:线程执行 Kernel 代码中定义的指令,访问私有寄存器(Registers)和线程块共享内存(Shared Memory)。

  • 独立性:理想情况下,每个线程应独立执行其任务,减少相互依赖,以实现最大并行效率。

2. 线程块 (Block)

线程块是线程的分组容器,是线程间协作的基本单位。

  • 定义:一组协作的线程集合,它们共同执行 Kernel 的一个子任务。

  • 标识:每个线程块都有一个内置的唯一标识符blockIdx

    • blockIdx.xblockIdx.yblockIdx.z:线程块在网格内的坐标。
  • 维度:线程块可以定义为一维、二维或三维结构(dim3 blockDim;)。

    • blockDim.xblockDim.yblockDim.z:定义了线程块中线程的数量和排列方式。
  • 协作与通信:

    • 共享内存:块内的线程可以通过共享内存(Shared Memory)进行高速数据交换。

    • 同步屏障:块内的线程可以通过__syncthreads()函数进行同步,确保所有线程都到达某个执行点后才能继续,这对于数据依赖的算法至关重要。

  • 硬件映射:一个线程块内的所有线程保证会被调度到同一个SM(流多处理器)上执行。这保证了块内线程对共享内存的访问非常快。

3. 网格 (Grid)

网格是线程块的最高级容器,代表一次完整的 Kernel 启动。

  • 定义:由所有线程块组成的集合,是整个并行计算任务的总和。

  • 标识:网格没有内置的索引变量,它的维度由主机在 Kernel 启动时通过gridDim参数指定。

    • gridDim.xgridDim.ygridDim.z:定义了网格中线程块的数量和排列方式。
  • 协作与通信:网格中的不同线程块原则上是相互独立的

    • 无法直接同步:不同线程块之间不能使用__syncthreads()进行同步。

    • 全局内存通信:线程块之间只能通过访问速度较慢的全局内存(Global Memory)进行通信。如果需要全局同步,必须终止当前 Kernel,在主机端同步后,再次启动一个新的 Kernel。

  • 硬件映射:网格中的线程块由 GPU 调度器分发到不同的 SM 上并行执行。


4. 如何计算全局唯一索引

理解线程层次结构的关键在于知道如何将线程的局部坐标 (blockIdxthreadIdx) 转换为它在整个网格中的全局唯一索引,即它应该处理的数据元素的索引iii

4.1 一维索引计算

对于大多数简单的一维数据结构(如向量),全局索引iii的计算公式如下:

i=blockIdx.x×blockDim.x+threadIdx.xi = \text{blockIdx.x} \times \text{blockDim.x} + \text{threadIdx.x}i=blockIdx.x×blockDim.x+threadIdx.x

变量含义
blockIdx.x\text{blockIdx.x}blockIdx.x当前块的索引
blockDim.x\text{blockDim.x}blockDim.x每个块的线程数
threadIdx.x\text{threadIdx.x}threadIdx.x线程在块内的索引

4.2 二维索引计算(例如矩阵)

对于二维数据结构(如矩阵),我们通常需要计算两个索引rrr(行)和ccc(列):

r=blockIdx.y×blockDim.y+threadIdx.yc=blockIdx.x×blockDim.x+threadIdx.xr = \text{blockIdx.y} \times \text{blockDim.y} + \text{threadIdx.y} \\ c = \text{blockIdx.x} \times \text{blockDim.x} + \text{threadIdx.x}r=blockIdx.y×blockDim.y+threadIdx.yc=blockIdx.x×blockDim.x+threadIdx.x

变量含义
blockIdx.y\text{blockIdx.y}blockIdx.y块的行索引
threadIdx.y\text{threadIdx.y}threadIdx.y线程在块内的行索引
blockDim.y\text{blockDim.y}blockDim.y每个块的线程行数

5. 层次结构与硬件的映射关系

CUDA 层次结构的设计直接反映了 NVIDIA GPU 的硬件结构,这是高效性能的关键:

  1. Grid→\toGPU:整个网格映射到整个 GPU。

  2. Block→\toSM:每个线程块被调度到一个 SM 上执行。多个块可以按时间片轮转的方式在同一个 SM 上执行,或者同时在多个 SM 上执行。

  3. Thread→\toCore:块内的线程最终映射到 SM 内部的 CUDA 核心。

    • Warp:SM 实际上是以Warp(32 个连续线程)为单位进行指令调度和执行的。一个线程块会被分解成一个或多个 Warp。

性能考虑:分块大小

选择合适的线程块大小 (blockDim) 至关重要:

  • 太小:无法充分利用 SM 的资源(如寄存器、共享内存),浪费硬件并行潜力。

  • 太大:可能超出 SM 能够提供的资源限制(如最大线程数、共享内存大小),导致 Kernel 启动失败或运行效率降低。

通常,blockDim选择 128、256 或 512,并且应为 32(Warp 大小)的倍数,以避免线程分化带来的性能损失。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 15:48:23

霍尔电流传感器防护措施,能延长使用寿命么?

在工业电力系统、新能源汽车、光伏逆变器等场景中,霍尔电流传感器是实现电流精准监测与安全控制的核心器件。然而,其工作环境常伴随强电磁干扰、温度波动、振动冲击及粉尘潮湿等问题,易导致传感器信号漂移、绝缘失效甚至永久性损坏。科学的防…

作者头像 李华
网站建设 2026/6/10 13:43:52

Python的getattr()和setattr()的用法

在 Python 中,getattr() 和 setattr() 是内置函数,用于动态获取和动态设置对象的属性(包括方法,这个要记住,很有用),是实现反射(运行时操作对象属性)的核心工具。一、基础…

作者头像 李华
网站建设 2026/6/9 21:12:16

终极指南:用Katana打造高效学术爬虫,10倍提升文献采集效率

终极指南:用Katana打造高效学术爬虫,10倍提升文献采集效率 【免费下载链接】katana 下一代爬虫和蜘蛛框架。 项目地址: https://gitcode.com/GitHub_Trending/ka/katana 你是否正在为海量学术文献的收集而烦恼?手动下载论文效率低下&a…

作者头像 李华
网站建设 2026/6/10 15:49:01

华为FreeBuds Pro 5听力检测绝了!在家就能搞定,超方便~

华为FreeBuds Pro 5的听力检测和助听功能真的太实用了!不用跑医院,在家找个安静角落,打开华为创新研究App,六七分钟就能完成检测,还会生成听力报告,清楚知道自己听力状况。 要是有轻中度听损,开…

作者头像 李华
网站建设 2026/6/10 14:57:32

PCB镀金的隐形杀手:如何攻克黑盘、针孔与金丝短路?

镀金工艺并非总是一帆风顺,黑盘、针孔、金丝短路堪称三大“隐形杀手”,轻则导致焊接失效,重则引发整板报废。本期聚焦镀金工艺的常见缺陷成因与攻克方案,为工程师提供一本“排雷手册”。 ​ 黑盘现象:镍层氧化的致命陷…

作者头像 李华