Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 系统与高性能 / Systems & Performance

计算系统 / Computing Systems

1. 计算系统:计算机如何执行与加速程序

2. 从 C++ 源码到 CPU 执行

3. CPU 流水线、乱序执行与分支预测

4. Cache、一致性、伪共享与 NUMA

5. GPU、SM、Warp 与显存

6. 计算执行模型:程序怎样映射到机器

7. SIMD 与编译器向量化

8. C++ 多线程与 OpenMP

9. CUDA 平台与编程模型

10. CUDA Kernel、内存与性能

11. CPU-GPU 异构流水线

12. MPI 与分布式并行

13. 并行算法模式

14. 性能模型与工具

15. 递进学习项目:从单线程到集群

历史完整正文 / Original Deep Dives

1. 历史完整正文:统一前文章逐篇保留

原体系结构与硬件 / Original Architecture

1. 硬件编程与高性能计算:一张可走通的学习地图 / A Practical Learning Map for Hardware Programming and HPC

2. 计算机体系结构:CPU、内存与 GPU / Computer Architecture: CPUs, Memory, and GPUs

3. 计算机架构基础——为什么 GPU 比 CPU 更快 / Computer Architecture Fundamentals: Why GPUs Outperform CPUs

4. 并行计算理论——30 天训练能优化到多快? / Parallel Computing Theory and the Limits of Training Acceleration

5. GPU 架构深入——上万个核心如何分工协作 / GPU Architecture and Massive Parallel Execution

6. CUDA 编程模型——把矩阵乘法映射到 GPU / The CUDA Programming Model for Mapping Matrix Multiplication to GPUs

7. CUDA 内存管理——百亿参数如何装进显存 / CUDA Memory Management for Large Models

8. CUDA 性能优化——从 30 天缩短到 10 天 / CUDA Performance Optimization

9. CPU 并行编程——OpenMP 与 SIMD 向量化 / CPU Parallel Programming with OpenMP and SIMD

10. HPC 集群与 MPI——多节点分布式训练 / HPC Clusters and MPI for Distributed Training

11. 异构计算——CPU 与 GPU 如何协同工作 / Heterogeneous Computing with CPUs and GPUs

12. 深度学习训练优化实战——从 30 天到 3 天 / Deep Learning Training Optimization from Thirty Days to Three

13. 性能分析工具——找到真正的瓶颈 / Performance Analysis Tools for Finding Real Bottlenecks

14. NPU 全景——昇腾/寒武纪/TPU/苹果生态 / The NPU Landscape: Ascend, Cambricon, TPU, and Apple

15. 未来趋势——2030 年的计算机会是什么形态 / Future Computing Trends Toward 2030

16. 硬件与高性能计算:从“程序为什么慢”开始 / Hardware and HPC Starting from Why Programs Are Slow

原并行计算 / Original Parallel Computing

1. 并行计算:从 SIMD 到 MPI / Parallel Computing from SIMD to MPI

2. 并行计算全景:从晶体管、CPU、GPU 到计算集群 / Parallel Computing from Transistors, CPUs, and GPUs to Clusters

3. 并行计算基础:任务分解、加速比与可扩展性 / Parallel Computing Fundamentals: Decomposition, Speedup, and Scalability

4. 处理器体系结构:从指令流水线到多核芯片 / Processor Architecture from Instruction Pipelines to Multicore Chips

5. CPU 并行:多线程、SIMD、Cache 一致性与 NUMA / CPU Parallelism with Threads, SIMD, Cache Coherence, and NUMA

6. 内存层次:Cache、带宽、局部性与一致性 / Memory Hierarchies, Bandwidth, Locality, and Coherence

7. GPU 体系结构:SIMT、Warp、SM 与吞吐优先设计 / GPU Architecture with SIMT, Warps, and Streaming Multiprocessors

8. CUDA 编程模型:Thread、Block、Grid 与内存协作 / CUDA Threads, Blocks, Grids, and Cooperative Memory Access

9. 并行算法模式:Map、Reduce、Scan、Stencil 与任务图 / Parallel Patterns: Map, Reduce, Scan, Stencil, and Task Graphs

10. 异构计算:CPU、GPU、NPU 如何协同工作 / Heterogeneous Computing with CPUs, GPUs, and NPUs

11. 分布式并行:MPI、集合通信、RDMA 与多机多卡 / Distributed Parallelism with MPI, Collective Communication, and RDMA

12. 性能工程:测量、Roofline、瓶颈定位与优化闭环 / Performance Engineering with Measurement, Roofline, and Bottleneck Analysis

13. 并行计算实战:AI、CAE、图像与科学计算 / Parallel Computing for AI, CAE, Imaging, and Scientific Computing

14. 并行计算实践路线:从单核优化到多机多卡 / A Parallel Computing Project Path from Single-Core to Multi-Node GPUs

本页目录

CPU 并行:多线程、SIMD、Cache 一致性与 NUMA / CPU Parallelism with Threads, SIMD, Cache Coherence, and NUMA ​

📅 创建时间:2026-07-20 🏷️ 标签:#CPU #多线程 #SIMD #NUMA #OpenMP 📚 前置知识:[[02-processor-architecture]] 📚 相关知识:[[/02-systems-and-performance/02-computer-architecture-and-hardware/07-openmp-simd]] [[/01-cpp/06-concurrency/04-concurrency]]


1. CPU 并行的三个层次 ​

text
线程级并行:多个核心执行不同线程
数据级并行:一条 SIMD 指令处理多个元素
任务级并行:不同任务组成流水线或任务图
1
2
3

例如矩阵运算可以把行分给多个线程,每个线程内部再使用 AVX 指令一次计算多个浮点数。


2. 线程并行 ​

线程创建不是免费的 ​

创建和销毁线程涉及系统调用、栈空间和调度,因此工程中通常使用线程池。

text
任务提交 → 工作队列 → 固定数量工作线程 → 执行结果
1

线程数量并非越多越好:

  • 计算密集型任务通常接近物理核心数
  • I/O 密集型任务可以更多
  • 使用 SMT 时需要实际测量
  • 第三方数学库可能已经创建线程,避免嵌套过度并行

OpenMP 示例 ​

cpp
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
    output[i] = compute(input[i]);
}
1
2
3
4

OpenMP 适合逐步并行化规则循环,但仍需检查数据竞争和任务粒度。


3. SIMD 向量化 ​

标量加法一次处理一个元素:

text
a0+b0 → c0
1

256 位 AVX 指令可以一次处理 8 个 FP32:

text
[a0..a7] + [b0..b7] → [c0..c7]
1

编译器自动向量化偏爱:

  • 连续内存访问
  • 简单、固定次数的循环
  • 迭代之间没有依赖
  • 容易证明指针不重叠
  • 分支较少

不利示例 ​

cpp
for (int i = 1; i < n; ++i) {
    a[i] = a[i - 1] * 0.5f; // 当前迭代依赖前一次结果
}
1
2
3

这是循环携带依赖,不能直接并行执行各次迭代。


4. 数据竞争与同步 ​

cpp
counter++; // 读取、加一、写回,并非不可分割操作
1

多个线程同时修改会导致结果丢失。常用保护方式:

  • Mutex:保护复杂临界区
  • Atomic:保护简单原子状态
  • Reduction:每个线程局部计算,最后合并
  • 消息传递:避免共享可变状态

并行归约通常优于每次循环都锁住全局变量。


5. 伪共享 ​

即使线程修改不同变量,只要变量位于同一个 Cache Line,也可能互相使缓存失效。

cpp
struct Counters {
    long a; // 线程 A 修改
    long b; // 线程 B 修改,但可能与 a 在同一 Cache Line
};
1
2
3
4

常见处理方法:

  • 对高频写入的线程局部变量进行 Cache Line 对齐
  • 每线程维护局部统计值
  • 降低共享写入频率

伪共享不会造成结果错误,但会造成严重性能下降。


6. NUMA:内存也有远近 ​

多路服务器中,每颗 CPU 插槽通常连接自己的本地内存。

text
CPU 0 ─ 本地内存 0
  │
互联总线
  │
CPU 1 ─ 本地内存 1
1
2
3
4
5

CPU 0 访问内存 1 的延迟更高、带宽可能更低,这就是非统一内存访问 NUMA。

NUMA 优化原则 ​

  • First Touch:由实际使用数据的线程首次初始化数据
  • 线程绑定:避免线程在不同 NUMA 节点之间迁移
  • 数据分区:让线程主要访问本地内存
  • 测量远程访问比例,而不是凭感觉绑定

7. CPU 并行适用场景 ​

CPU 更适合:

  • 分支复杂、任务差异大的计算
  • 数据规模较小、要求低延迟的计算
  • 图遍历、搜索、编译、数据库执行
  • 操作系统和 I/O 协调
  • GPU kernel 前后的数据准备与控制

GPU 更适合并不意味着 CPU 不重要。多数异构应用都依赖 CPU 组织整个执行流程。


历史 CPU 并行补充 ​

本页保留合并前的 CPU 并行说明。

当前版本增加线程池、调度、取消、异常和实验记录。

线程池 ​

线程池复用 Worker,减少创建成本。

需要定义队列、并发、取消和关闭。

中央队列 ​

实现简单,可能形成锁和 Cache 热点。

Work Stealing ​

每线程本地队列改善不规则负载。

窃取增加调度与局部性成本。

有界队列 ​

有界队列提供背压。

无界任务会消耗内存并提高尾延迟。

静态调度 ​

适合规则且成本相近的循环。

调度少,局部性更可预测。

动态调度 ​

适合成本不均任务。

Chunk 需要在调度与均衡之间选择。

Reduction ​

使用线程局部结果和树形合并。

减少锁与原子争用。

锁 ​

粗锁容易正确但并行度低。

细锁增加死锁和维护复杂度。

条件变量 ​

等待状态谓词,并处理虚假唤醒。

通知与状态修改构成完整协议。

原子 ​

原子只保护对应对象。

Relaxed 不发布周围普通数据。

False Sharing ​

不同字段位于同一 Cache Line 也会争用。

线程局部、分片和对齐是候选方案。

NUMA ​

首次触碰、亲和性和数据分片影响远近。

每节点队列和内存池可减少远端访问。

SIMD ​

线程与 SIMD 可以分层组合。

布局、别名和循环依赖影响向量化。

异常 ​

Worker 捕获异常并传回任务结果。

不能悄悄终止线程或丢失任务状态。

取消 ​

协作式取消在安全点检查。

取消后释放锁、Buffer、文件和第三方资源。

关闭 ​

停止新任务,取消或 Drain,最后 Join。

不允许在 Worker 仍运行时销毁依赖对象。

调试 ​

  • Thread Sanitizer;
  • 死锁检测;
  • 压力测试;
  • 日志关联;
  • 单线程对照;
  • 故障注入。

Profile ​

WPA CPU Precise 查看 Running/Ready/Wait。

VTune Threading 查看并行度、同步和负载不均。

扩展曲线 ​

测量线程数变化。

记录时间、加速比、效率、锁、带宽和 NUMA。

历史版本边界 ​

OpenMP Runtime、调度器和处理器拓扑随环境变化。

旧线程数建议不能直接套用。

当前课程映射 ​

当前文章新增:

  • 线程池生命周期;
  • 队列;
  • 静态/动态调度;
  • Reduction;
  • 原子顺序;
  • 取消与异常;
  • Profile;
  • 实验记录。

阅读完成标准 ​

应能:

  • 设计线程池;
  • 选择调度;
  • 管理同步;
  • 识别 False Sharing;
  • 处理 NUMA;
  • 组合 SIMD;
  • 取消与关闭;
  • 验证扩展。

归档复现记录 ​

  • 来源提交;
  • CPU;
  • 核心与 SMT;
  • NUMA;
  • 编译器;
  • OpenMP/线程库;
  • 优化选项;
  • 输入;
  • 线程数;
  • 调度;
  • Chunk;
  • 亲和性;
  • First Touch;
  • SIMD 报告;
  • 锁等待;
  • 带宽;
  • 原始样本;
  • 正确性;
  • 当前差异。

复现实验应从单线程基线开始。 线程数结论只适用于记录的硬件、输入和运行库。 性能提升不能以数据竞争、泄漏或取消失效为代价。 所有结论都应保留可复现命令。

章节检查清单 ​

  • 循环迭代是否相互独立?
  • 任务粒度是否显著大于调度成本?
  • 是否存在共享写入和伪共享?
  • 编译器是否成功向量化?
  • 线程和数据是否跨越 NUMA 节点?
  • 数学库是否已经在内部并行?

下一篇:[[04-memory-hierarchy]]

最后更新于:

Pager
上一篇4. 处理器体系结构:从指令流水线到多核芯片 / Processor Architecture from Instruction Pipelines to Multicore Chips
下一篇6. 内存层次:Cache、带宽、局部性与一致性 / Memory Hierarchies, Bandwidth, Locality, and Coherence

持续记录,持续成长

Copyright © Tidenflow