CPU 如何理解世界
同一段 0101,可以是数字、指令或像素——解释规则决定含义。
内存里某地址的 8 个字节是 01001000 01100101 01101100 01101100 01101111——它可以是整数 72、字符 'H',也可以是某条机器指令的操作数。硬件本身不自带「意义」,CPU 靠指令集和程序约定给 bit 模式赋予含义。
本篇说明:取指、译码、执行如何运转;数字、指针、指令如何在同一套 bit 流里共存。
直觉:同一本字典,不同读法
一串汉字「银行」:在金融文章里是金融机构,在地理文章里可能是河岸。bit 串也一样:0x48 在 ASCII 表是 'H',在 int8 解释下是 72,在机器码里可能是某条 mov 的一部分。解释上下文(类型、段寄存器、当前指令)决定读法。
定义:冯·诺依曼架构要点
- 程序与数据同存于可寻址内存(统一地址空间)。
- PC(Program Counter)指向下一条要执行的指令地址。
- 指令周期:取指(Fetch)→ 译码(Decode)→ 执行(Execute)→ 写回(Writeback),现代 CPU 流水线并行多指令,主频常见 2–5 GHz(每核每秒数十亿周期)。
典型 64 位 x86-64 寄存器:RAX、RBX… 各 64 bit;通用寄存器 16 个量级,远小于内存(GB 级)——所以要有 Cache 与内存层次(后文详述)。
例子一:加法在硬件里是什么
伪代码 a = b + c,编译后可能变成:
; 示意:b 在 RDI,c 在 RSI,结果写 RAX
mov rax, [rdi] ; 从内存读 b 的 8 字节到 RAX
add rax, [rsi] ; RAX += 内存中的 c
mov [rdx], rax ; 结果写回 a 的地址add 在硅片里是加法器:对两个 64 bit 输入逐位全加器链,带进位,1 个时钟周期量级(实际还依赖流水线深度)。没有「加」这个中文字,只有 bit 模式 000000xx 触发 ALU 走加法通路。
例子二:同一段内存,两种视图
import struct
# 4 字节:小端存 int32 值 16909060 (0x01020304)
raw = bytes([0x04, 0x03, 0x02, 0x01])
as_int = struct.unpack('<i', raw)[0]
as_bytes = list(raw)
print(as_int, as_bytes) # 16909060 [4, 3, 2, 1]C 语言里 (int*)p 与 (char*)p 访问同一地址,读出的「意义」不同——这就是类型 punning 的底层原因(严格别名规则在语言层限制此类写法)。
量化:一次「理解」有多快?
| 指标 | 典型值(桌面 CPU,2024 量级) |
|---|---|
| 主频 | 3–5 GHz |
| 每周期 IPC | ~2–4(依赖 workload) |
| L1 Cache 延迟 | ~4 cycles ≈ 1 ns |
| 主内存 DRAM 延迟 | ~100 ns |
| L3 命中 vs 内存 miss | 差 30–50 倍 很常见 |
CPU「理解」世界的方式是:在纳秒级把 bit 当作指令执行,或当作数字运算;慢的是等内存(AI 训练里 GPU 也在和同样的问题搏斗)。
分支与预测:世界不只有线性
def abs_val(x):
if x >= 0: # 编译成 cmp + 条件跳转
return x
return -xif 会变成「比较 + 跳转指令」。分支预测错一次,流水线 flush 可能损失 10–20 周期。循环友好的数值代码(矩阵乘)比分支杂乱的业务逻辑更「CPU 友好」——后面 GPU/SIMD 篇会呼应这一点。
指令集:x86 与 ARM 的「方言」
同一串 bit,在 x86-64 与 ARM64 上可能是不同指令——这叫 ISA(Instruction Set Architecture)。Apple M 系列跑 ARM64;云服务器 x86 居多;AWS Graviton 是 ARM。Python/PyTorch 轮子要分平台编译,因为机器码 bit 模式不兼容。
典型 x86 指令长度 1–15 字节 变长;ARM64 常固定 4 字节,解码更简单,功耗更低。AI 推理在 GPU 上跑 CUDA(NVIDIA 私有 ISA),CPU 负责喂数据——heterogeneous computing 里每种处理器各认各的 bit 方言。
想深入到具体指令,各家 ISA 的官方参考手册:
- x86 / x86-64:Intel® 64 and IA-32 Architectures Software Developer's Manual(Intel 与 AMD 共同定义 x86-64,Intel SDM 是最常用的一份)。
- ARM64(AArch64):Arm Architecture Reference Manual for A-profile(即 Arm ARM,编号 DDI0487,涵盖 A64 指令集)。
- CUDA(NVIDIA 私有 ISA):PTX ISA(PTX 是对外公开的虚拟 ISA;真正落到硬件的 SASS 未完整公开)。
栈、堆与寄存器:bit 住在哪里
函数调用时,返回地址、局部变量压在 栈(向下增长);malloc/new 的对象在 堆。寄存器只有 几十×64 bit,装不下 16 GB 模型——大数组必在内存,寄存器暂存循环变量和指针。
// 示意:指针 p 本身是 8 字节,指向堆上 1e9 个 float 的的首地址
float *p = malloc(1e9 * sizeof(float)); // ~4 GBCPU「理解」指针 = 把 8 字节当作无符号整数地址,经 MMU 查页表得到物理地址,再读 DRAM——每一次数组访问都是 bit 地址解码。
微架构一瞥:超标量与乱序
现代 CPU 每周期可 退休多条指令(IPC>1):乱序执行在依赖允许时先算后面的 independent 指令。分支预测错则 flush 10–20 周期——Attention 里 if (mask) 少,GEMM 内层循环无分支,故 AI 热点 kernel 喜 CPU/GPU 无分支 SIMD。
Out-of-order 不改变语义:as-if sequential,程序员仍见单线程内存模型(C11 memory_order 另论)。多线程写同一 cache line 才需 atomic——PyTorch 分布式训练 all-reduce 走 NCCL,不靠 CPU 乱序救场。
场景实战:用 bit 视角读一条新闻
「某公司发布 405B 参数模型」——你应立刻换算:FP16 约 810 GB 权重,INT4 量化约 200 GB,单卡不可能,推理需 多卡 TP 或 MoE 激活子集。「在 10 TB 文本上训练」——UTF-8 磁盘 ~10 TB,token 数约 2–4 T(视语言混合),训练 FLOPs 量级 (Kaplan, 参数 token)。新闻里的每个形容词都可换成 byte 和 FLOPs。
常见误区
- 「CPU 直接运行 Python」——Python 字节码由解释器或 JIT 转成机器码;你写的是语义层,CPU 只看机器码。
- 「64 位 CPU 只能算 64 位以内的数」——寄存器宽度是一次运算的「车道宽」;大整数、浮点、向量有专用指令扩展。
- 「内存里某处放着字符串 'Hello'」——存的是编码整数序列;是
'H'还是 72,取决于 load 指令后怎么用。
动手试一试
观察整数与 ASCII 的同一性(仅用于理解,勿在生产搞混类型):
n = 0x48656C6C6F # "Hello" 若按大端打包成 5 字节需截断,这里演示逐字符
chars = [0x48, 0x65, 0x6C, 0x6C, 0x6F]
print(''.join(chr(c) for c in chars))
print(sum(c << (8*i) for i, c in enumerate(reversed(chars))))小结
CPU 通过指令集架构把 bit 解释为操作与操作数;程序通过类型与 ABI 约定把 bit 解释为整数、浮点、指针、字符串。AI 推理程序最终也只是一串这样的指令,在数十亿晶体管上驱动矩阵运算。
下一篇:整数如何表示——有符号、无符号与溢出的精确规则。