Visual LabINTERACTIVE LEARNING
阶段 4 · 计算基础18 分钟

原子操作与归约:安全汇总并行结果

atomicAdd、直方图与竞争条件

大量 invocation 并行统计随机数据直方图,用 atomicAdd 避免多个线程覆盖同一计数。

LEARNING GOALS

先明确本课目标

1

声明 atomic<u32>

2

使用 atomicAdd

3

理解竞争条件与分层归约

MENTAL MODEL · 再建立心智模型

普通读-改-写不是一个不可分割操作;原子操作把竞争更新串成安全结果,但热点地址会限制并行度。

MINIMAL EXAMPLE

很多线程同时给同一个计数器加一会发生什么?

普通的读—改—写可能互相覆盖,形成 Race Condition。Atomic 操作保证一次修改不可分割,使并发 invocation 对共享整数的更新不会丢失。

最小例子wgsl
@group(0) @binding(0)
var<storage, read_write> bins: array<atomic<u32>>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3u) {
  let bin = values[id.x] % 8u;
  atomicAdd(&bins[bin], 1u);
}
  1. atomic 类型 WGSL 原子值使用 atomic<u32> 或 atomic<i32>,不能把普通 u32 当原子操作。
  2. 地址传入 atomicAdd 接收目标原子变量的引用与增量。
  3. 正确但可能争用 大量 invocation 命中同一地址时会序列化,分层归约通常更快。

所有 bin 的计数总和等于输入元素数量,不再因并发覆盖而随机变小。

本课概念
OPTIONAL · 按需查阅完整术语表与概念边界

遇到陌生术语时再展开,不打断主线实验。

展开⌄
LIVE EXPERIMENT · 先获得反馈

边改边运行

浏览器加载后会激活代码编辑器、独立运行环境与实时输出。

本课挑战

实现并行最大值与平均值归约。

DEEP DIVE · 实验之后

回到原理,解释刚才发生了什么

先用结果建立反馈,再按运行流程、核心原理和知识关系逐层深入。

CORE IDEA

核心讲解

01

何时需要原子

多个 invocation 可能同时更新同一地址时,普通加法会丢失更新。原子操作保证每次修改不可分割。

02

原子不是免费的

所有线程争用少数计数器会序列化。常见优化是先在 workgroup 内局部统计,再合并到全局。

OPTIONAL · 迁移时查阅WebGPU 与 WebGL2 对照

主线实验完成后,再用完整映射处理跨平台或跨 API 迁移。

展开⌄
API COMPARISON

WebGL2 没有通用 shader 原子与共享内存归约;WebGPU 可原生表达并发写冲突。

WebGL

通常用 blending、多 Pass 金字塔或 CPU 汇总绕开冲突,算法形状受渲染目标限制。

WebGPU

atomic 类型、workgroup memory 和 barrier 能构建直方图与分层归约。

不要原样搬运多 Pass 纹理归约;先判断是否可用组内归约减少全局原子竞争。