B-Queue

3_2.eps

B-Queue 是一种面向多核架构中核间通信的高效、实用的 单生产者-单消费者(SPSC)无锁队列,其设计旨在解决现有并发无锁队列(CLF queue)在真实应用中存在的性能退化与死锁难题。

背景动机

多核系统中,线程间通常通过共享内存进行通信,CLF 队列被广泛用于核心间通信。然而现有的方案(如 FastForward 和 MCRingBuffer)存在如下问题:

  1. 性能仅在理想条件(如 L1 缓存驻留)下突出,在真实系统中易受缓存抖动影响。
  2. 扩展性差,多队列并发使用时性能显著下降。
  3. 难以使用,需要复杂的参数调优或辅助机制来防止死锁。

B-Queue 的关键设计

1. 批处理(Batching)

  • 生产者和消费者各维护一对指针(head/batch_headtail/batch_tail),一次性探测一块可用槽位。
  • 减少缓存交互,提升性能,增强预取效率。

2. 回溯机制(Backtracking)

  • 当消费者发现当前批次为空时,自适应缩小批次大小,逐步逼近最近的有效数据槽位。
  • 避免死锁的关键机制:不再依赖额外线程或定时器来“唤醒”对方。
  • 复杂度低无垃圾数据注入,真正适用于实际系统。

3. 自适应回溯(Self-adaptive Backtracking)

  • 根据运行时状况调整初始批次大小,兼顾低延迟与高吞吐。
  • 若生产者忙,批次增大;若生产者不活跃,批次自动减小。

优势总结

  • 无需参数调优,跨平台适用性好。
  • 比 FastForward 和 MCRingBuffer 分别快最多 10x 和 5x(在真实 10Gbps 网络处理系统中测试)。
  • 稳定性强:即使在七个并发队列同时运行下性能也几乎无下降。
  • 延迟低、无死锁、易集成

实际应用场景

  • 高速网络数据处理系统。
  • 多核并行系统中的流水线化任务分解与通信。
  • 高频核心间数据传递(如实时视频处理、数据库操作等)。

那岂不是180核要32400个队列?

不用: B-Queue 是单生产者-单消费者(SPSC)

  • 每个 B-Queue 实例只连接两个线程(或核):一个生产者,一个消费者。
  • 只需要为“有通信需求”的核对之间建立队列
通信模式 队列数量估计 举例说明
全连接通信(每个核都可能给任意其他核发消息) O(n²) ≈ 32,400 个(180×179) 这确实是最坏情况,基本不可行
流水线通信(典型场景) O(n) 每个核仅与上下游通信,比如核 i 向 i+1 发送
N:1 或 1:N 扇出/扇入 O(n) 比如多个核向一个汇聚核发数据(1 aggregator + N workers)
分组通信(如 6 个核一组,共 30 组) O(n × g) 每组内部全连接最多 6² = 36 个队列,30 组则最多 1080 个
稀疏通信(most practical) 远小于 n² 多数核只和少数核通信,比如生产者写入共享 buffer,由 dispatcher 分发

✔ 典型策略一:拓扑感知的调度

  • 只为实际有数据依赖的核之间分配队列。
  • 很多核之间不直接通信,而是通过中间节点(调度核、中继核、共享缓冲)转发。

✔ 典型策略二:使用池化结构

  • 一些系统采用 工作窃取(work-stealing)+ 局部队列
    • 每个核维护自己的本地队列。
    • 少量全局共享队列(MPMC)作为 backup。
    • 不再是每对核都有专队列。

✔ 典型策略三:分层调度 + B-Queue 混合使用

  • 核按 NUMA 节点/Socket/Cache 层分组。
  • 组内高效通信用 B-Queue;组间低频通信用其他机制(如环形缓冲/事件驱动/队列池)。