← 返回索引 · 2026-02-23 · 0017

从 μs 到 ns:用 AVX/SIMD 向量化撮合引擎热路径(摘要)

原文首发于 TechNova: 从μs到ns:基于AVX指令集的次世代撮合引擎向量化革命

承接页(解决方案):https://technologynova.org/solution/

TL;DR

1) 为什么传统撮合循环会卡在微秒级?

典型撮合是“遍历订单簿 → 判断是否价格可成交 → 计算成交量 → 更新状态”。当订单簿深度很大(上千/上万档)时,热路径会被三类问题持续骚扰:

如果你已经做过对象池、避免频繁分配、把部分结构改成数组、把序列器与撮合单线程绑定等“常规低延迟套路”,那下一步通常就是:别再幻想 SISD 能带来数量级收益,改用数据并行(SIMD)。

关键要点 / 常见坑(工程视角)

2) SIMD/AVX 真正解决的是什么问题?

SIMD(Single Instruction, Multiple Data)做的事很朴素:用一条指令对多个数据执行同一操作。 在 AVX2 下,一个 256-bit 寄存器可以同时放 4 个 double 价格;一条比较指令就能一次算出 4 个“是否可成交”。

更关键的是:把“每次循环一个 if”变成“每批 4 个结果的位掩码”,能显著减少分支与循环次数,把热路径更像是在做“批处理扫描”, CPU 的前端(取指/分支/流水)压力更小。

3) 让订单簿 SIMD-Ready:AoS → SoA + 对齐

原文强调了一个很现实的结论:树/链表是 SIMD 的天敌。要向量化,你需要把核心数据改成能连续加载的布局。 两种常见布局:

同时要注意对齐(AVX2 典型是 32 字节对齐)。工程上通常会使用 alignas + 对齐分配器来保证 vector 的底层地址满足要求。

4) 向量化撮合循环:比较向量化,更新用掩码驱动

向量化版本的核心步骤可以概括为:

  1. 把 taker 价格广播到向量寄存器(4 个 lane 都是同一个价格)。
  2. 一次加载 4 个 maker 价格。
  3. 做向量比较(<= 或 >=,取决于买/卖方向)。
  4. movemask 把比较结果变成整数 bitmask(例如 0b0111 表示前 3 个匹配)。
  5. 基于 bitmask 逐个处理匹配项:计算成交量、更新数量、生成回报;若 mask 为 0 且订单簿有序,可提前退出。

这个结构的好处是:把“可并行的比较”交给 SIMD,剩下“必须串行的状态更新”由掩码驱动。 你不会得到 100% 的 4 倍加速,但通常能在热路径上明显降低比较与分支开销,尤其对 P99 很友好。

适用场景

承接页 CTA

如果你的撮合引擎已经做完“应用层常规优化”,但 P99/P999 仍被 cache miss 与分支拖累,可以按“三段式”评审落地路线: 1) 先把订单簿改成连续内存布局(数组/分块/SoA); 2) 再把最热的比较/扫描环节向量化(AVX2/AVX-512); 3) 最后用基准与回归测试守住正确性与尾延迟。 更系统的落地路径与架构咨询可参考: https://technologynova.org/solution/

原文链接:
https://technologynova.org/…/