标签:Go / 无锁队列 / Benchmark / 性能测试 / zhenyi-base
zhenyi-base zqueue 基准测试分享
前言
在之前的系列文章里,我们逐一介绍了 zhenyi-base 中实现的各类并发队列------从基础的无锁 SPSC / MPSC 环形队列,到基于 sync.Mutex 的 Queue[T](满时丢弃 / 满时扩容两种策略)、双缓冲的 SmartDouble、堆结构的优先级队列,以及作为对照基线的 Go 原生 channel。每一种队列的设计取舍与适用场景,我们都专门聊过。
这一期我们不谈原理,只聊一件事:这些队列到底有多快?
本文基于统一的基准测试框架,在固定环境下对全部队列做了覆盖「载荷大小 × 并发度 × API 模式」的矩阵式压测,用数据说话------既看延迟,也看内存分配与吞吐,帮你在真实选型时心里有底。
不过基准测试受环境、参数、实现细节影响很大,难免有测不准、或某处对比不够公平的地方。如果文中数据有偏差、或你觉得哪个环节对比不够严谨,欢迎在评论区或 Issue 里指出来------大家一起把测试做得更准、更客观。
一、测试环境
| 项目 | 配置 |
|---|---|
| 平台 | Linux |
| CPU | Intel(R) Xeon(R) CPU @ 2.20GHz |
| Go 版本 | 1.24 |
| 测试并发 | P1 / P4 / P16 / P64 |
| 载荷大小 | Small(256B) / Medium(4KB) / Large(64KB) |
| API 模式 | SingleSingle / SingleBatch / BatchSingle / BatchBatch |
注意:SmartDouble 仅支持 SingleBatch / BatchBatch 两种 API;Priority 仅支持 SingleSingle。SPSC 队列(SPSCBounded / SPSCUnbounded)仅有 P1 并发度数据。
二、各队列性能数据
2.1 SPSC 队列(SPSCBounded / SPSCUnbounded)
SPSC 队列只有单生产者单消费者场景,仅 P1 并发度。
2.1.1 SPSCBounded(有界 SPSC 环形队列)
| 载荷 | P1/SingleSingle (ns/op) | P1/BatchBatch (ns/op) | MB/s (BatchBatch) |
|---|---|---|---|
| Small | 77.44 | 50.33 | 5086 |
| Medium | 986.4 | 847.1 | 4835 |
| Large | 21530 | 19840 | 3303 |
内存分配:Small/Medium 0 B/op,Large/BatchBatch 17 B/op。

2.1.2 SPSCUnbounded(无界 SPSC 链表队列)
| 载荷 | P1/SingleSingle (ns/op) | P1/BatchBatch (ns/op) | MB/s (BatchBatch) |
|---|---|---|---|
| Small | 191.4 | 168.6 | 1518 |
| Medium | 829.8 | 768.8 | 5327 |
| Large | 20843 | 24526 | 2671 |
内存分配:Small 0 B/op;Medium 1至6 B/op;Large 405至764 B/op。

2.2 MPSCBounded / MPSCPadded(有界 MPSC)
| 载荷 | MPSCBounded P1/Single (ns/op) | MPSCBounded P64/BatchBatch (ns/op) | MPSCPadded P1/Single (ns/op) | MPSCPadded P64/BatchBatch (ns/op) |
|---|---|---|---|---|
| Small | 111.5 | 55.76 | 111.6 | 55.61 |
| Medium | 994.9 | 933.8 | 875.5 | 932.8 |
| Large | 20132 | 18516 | 19649 | 18512 |
Small/Medium P1/Single 和 Small P64/BatchBatch 为
0 B/op;Medium/Large P64/BatchBatch 有小量分配(25至994 B/op),整体仍属极低水平。

2.3 MPSCUnbounded(无界 MPSC 链表队列)
| 载荷 | P1/Single (ns/op) | P64/BatchBatch (ns/op) | 分配 (P64/BatchSingle) |
|---|---|---|---|
| Small | 273.5 | 356.0 | 203 B/op |
| Medium | 919.4 | 1883 | 4514 B/op |
| Large | 21860 | 27966 | 59489 B/op |


2.4 QueueT(基于 Mutex 的环形队列)
QueueResize 和 QueueDrop 共享同一套 Queue[T] 实现(sync.Mutex 环形队列),区别仅在于队列满时的处理策略。
2.4.1 QueueDrop --- FullPolicyDrop(满时丢弃)
队列满时 Enqueue() 直接返回 false,不阻塞、不扩容、不分配内存。
| 载荷 | P1/Single (ns/op) | P4/Single (ns/op) | P16/Single (ns/op) | P64/Single (ns/op) |
|---|---|---|---|---|
| Small | 180.4 | 155.8 | 176.5 | 201.3 |
| Medium | 1912 | 1760 | 565.7 | 525.7 |
| Large | 29829 | 13317 | 10475 | 12216 |
内存分配:所有场景 0 B/op, 0 allocs/op。

满队列丢弃下的吞吐量 :在 BatchSingle / BatchBatch 模式下,超出容量直接返回失败、零内存分配,因此高并发批量入队能维持极高吞吐(参考:SPSCBounded Small P1/BatchBatch 为 5086 MB/s)。
| 载荷 | P1 (MB/s) | P4 (MB/s) | P16 (MB/s) | P64 (MB/s) |
|---|---|---|---|---|
| Small | 2987 | 20386 | 19023 | 19722 |
| Medium | 3529 | 32265 | 31330 | 32694 |
| Large | 3220 | 16170 | 18149 | 18570 |


2.4.2 QueueResize --- FullPolicyResize(满时扩容)
队列满时自动扩容(cap × 2),入队永不失败,但扩容时会分配内存。
| 载荷 | P1/Single (ns/op) | P4/Single (ns/op) | P16/Single (ns/op) | P64/Single (ns/op) |
|---|---|---|---|---|
| Small | 225.5 | 518.1 | 832.3 | 757.8 |
| Medium | 1967 | 2404 | 6760 | 4728 |
| Large | 64947 | 77979 | 128132 | 103230 |
内存分配:Small P1 3 B/op,P4至P64 505至973 B/op;Medium P1 0 B/op,P4至P64 933至11353 B/op;Large 103274至201305 B/op。

2.5 SmartDouble(双缓冲队列)
SmartDouble 仅支持 SingleBatch / BatchBatch API,下表使用 BatchBatch。
| 载荷 | P1/BatchBatch (ns/op) | P4/BatchBatch (ns/op) | P16/BatchBatch (ns/op) | P64/BatchBatch (ns/op) |
|---|---|---|---|---|
| Small | 49.04 | 39.69 | 51.87 | 113.7 |
| Medium | 723.9 | 867.5 | 889.2 | 1028 |
| Large | 17318 | 16828 | 15488 | 16621 |
内存分配:Small 0 B/op;Medium P4/P16/P64 分别 1/6/27 B/op;Large P1/P4/P16/P64 分别 14/57/217/975 B/op。
实现方式:双缓冲 + sync.Mutex。


2.6 Priority(优先级队列)
Priority 仅支持 SingleSingle API。
| 载荷 | P1/Single (ns/op) | P4/Single (ns/op) | P16/Single (ns/op) | P64/Single (ns/op) |
|---|---|---|---|---|
| Small | 599.6 | 1723 | 2465 | 1877 |
| Medium | 3429 | 20914 | 22153 | 21347 |
| Large | 64271 | 361545 | 344674 | 296466 |
内存分配:Small P1/P4/P16/P64 分别 2/542/1040/1163 B/op;Medium P4/P16/P64 分别 9840/19179/20010 B/op;Large P4/P16/P64 分别 186024/250971/250974 B/op。
实现方式:堆结构,入队/出队 O(log n)。


2.7 ChanBuffered / ChanUnbuffered(Go 标准 channel 基线)
| 载荷 | ChanBuffered P1/Single (ns/op) | ChanUnbuffered P1/Single (ns/op) |
|---|---|---|
| Small | 168.9 | 353.1 |
| Medium | 1575 | 481.0 |
| Large | 18878 | 6103 |
内存分配:所有场景 0 B/op, 0 allocs/op。

三、跨队列整体对比
以下对比均使用 SingleSingle API。SmartDouble 不支持该 API,已排除。SPSC 队列仅有 P1 数据,P64 对比中已排除。
3.1 各队列延迟对比(不同载荷 × 并发度)

3.2 各队列内存分配汇总
各队列在其最大并发度(P64 或 P1)下、SingleSingle API 的内存分配量(SPSC 队列仅有 P1 数据)。SPSCBounded 在 BatchBatch 下 Large 峰值约 17 B/op。
| 队列 | Small (B/op) | Large (B/op) |
|---|---|---|
| SPSCBounded (P1) | 0 | 0 |
| MPSCBounded (P64) | 0 | 0 |
| MPSCPadded (P64) | 0 | 0 |
| QueueDrop (P64) | 0 | 0 |
| MPSCUnbounded (P64) | 182 | 52955 |
| QueueResize (P64) | 973 | 201305 |
| Priority (P64) | 1163 | 250974 |
| ChanBuffered (P64) | 0 | 0 |
| ChanUnbuffered (P64) | 0 | 0 |

四、API 与并发度分析
4.1 批量 API vs 单次 API
同一队列下,批量 API 与单次 API 的 ns/op 对比:
| 队列 | 载荷 | 单次 (ns/op) | 批量 (ns/op) |
|---|---|---|---|
| MPSCBounded | Small/P1 | 111.5 (SingleSingle) | 74.12 (BatchBatch) |
| MPSCBounded | Small/P64 | 147.7 (SingleSingle) | 55.76 (BatchBatch) |
| SPSCBounded | Small/P1 | 77.44 (SingleSingle) | 50.33 (BatchBatch) |
| QueueDrop | Small/P4 | 155.8 (SingleSingle) | 12.56 (BatchSingle) |

4.2 并发度对性能的影响
以 MPSCBounded/Small 为例:
| 并发度 | SingleSingle (ns/op) | BatchBatch (ns/op) |
|---|---|---|
| P1 | 111.5 | 74.12 |
| P4 | 141.3 | 52.61 |
| P16 | 144.3 | 54.08 |
| P64 | 147.7 | 55.76 |

五、完整数据与复现
完整 benchmark(114 组测试):
📎 docs/benchmark/zqueue_matrix_results.txt
复现方法:
bash
git clone https://github.com/aiyang-zh/zhenyi-base.git
cd zhenyi-base/zqueue
go test -bench=BenchmarkMatrix -benchmem -count=3 > result.txt
⭐ 觉得有帮助的话点个 Star 吧,有问题欢迎提 Issue
完整源码:github.com/aiyang-zh/z...
交流群:QQ 群 1098078562
公众号:Zhenyi-io