性能概览

SpanSerializer 是基于 SpanReader/SpanWriter 的零流、无处理器链高性能序列化器,适用于 RPC 通信和文件读写。
测试结论:SpanSerializer(反射路径) 比 Binary 快 9~21 倍;实现 ISpanSerializable 接口后可再快 2.5~4 倍,且零堆分配。


测试环境

项目

CPU

Intel Core i9-10900K @ 3.70 GHz(20 逻辑核心)

OS

Windows 10 22H2 (19045.6456)

.NET

.NET 10.0

BenchmarkDotNet

v0.15.8

编译模式

Release


测试方法

三条序列化路径:

路径

说明

SpanSerializer(反射)

普通 POCO,通过编译委托(Expression.Lambda)序列化

SpanSerializer(ISpanSerializable)

实现接口,零反射手写路径

Binary

基于 MemoryStream + 处理器链的传统序列化

测试模型:

  • SimpleModel:5 个字段(Int32/String/Boolean/DateTime/Double)
  • NestedModel:4 个字段 + 内嵌 SimpleModel
  • FastModel:同 SimpleModel,但实现 ISpanSerializable

测试维度:单次操作(序列化/反序列化)、批量操作(100 / 1000 条)、多线程并发(1 / 4 / 8 / 20 / 32 线程)。


测试结果

1. 单次序列化

基准(Baseline)= Span_Simple序列化_到Span

方法

Mean

Error

StdDev

Ratio

Gen0

Allocated

Alloc Ratio

Span_Simple序列化_到Span (Baseline)

59.03 ns

0.432 ns

0.067 ns

1.00

0.0092

96 B

1.00

Span_Simple序列化_池化包

64.80 ns

1.473 ns

0.382 ns

1.10

0.0092

96 B

1.00

Span_Nested序列化_到Span

110.56 ns

1.166 ns

0.303 ns

1.87

0.0137

144 B

1.50

Span_Fast序列化_到Span

23.49 ns

0.113 ns

0.029 ns

0.40

-

0 B

0.00

Span_Fast序列化_池化包

29.26 ns

0.059 ns

0.015 ns

0.50

-

0 B

0.00

Binary_Simple序列化

800.83 ns

15.063 ns

3.912 ns

13.57

0.1926

2016 B

21.00

Binary_Nested序列化

1,222.42 ns

19.373 ns

2.998 ns

20.71

0.2632

2752 B

28.67

2. 单次反序列化

基准(Baseline)= Span_Simple反序列化

方法

Mean

Error

StdDev

Ratio

Gen0

Allocated

Alloc Ratio

Span_Simple反序列化 (Baseline)

111.96 ns

1.599 ns

0.415 ns

1.00

0.0175

184 B

1.00

Span_Nested反序列化

219.83 ns

2.998 ns

0.464 ns

1.96

0.0312

328 B

1.78

Span_Fast反序列化

75.72 ns

0.726 ns

0.189 ns

0.68

0.0083

88 B

0.48

Binary_Simple反序列化

1,008.17 ns

14.916 ns

3.874 ns

9.00

0.2270

2392 B

13.00

Binary_Nested反序列化

1,747.46 ns

10.144 ns

2.634 ns

15.61

0.3204

3360 B

18.26

3. 批量操作(100 / 1000 条 SimpleModel)

基准(Baseline)= Span_批量序列化(同 Count 分组)

Count

方法

Mean

Error

StdDev

Ratio

Gen0

Allocated

Alloc Ratio

100

Span_批量序列化 (Baseline)

5.497 μs

0.100 μs

0.016 μs

1.00

0.9155

9.38 KB

1.00

100

Span_批量反序列化

10.695 μs

0.191 μs

0.050 μs

1.95

1.7548

17.97 KB

1.92

100

Binary_批量序列化

55.637 μs

0.552 μs

0.143 μs

10.12

9.2773

94.89 KB

10.12

100

Binary_批量反序列化

76.196 μs

0.806 μs

0.209 μs

13.86

10.254

105.83 KB

11.29

1000

Span_批量序列化 (Baseline)

55.577 μs

0.681 μs

0.177 μs

1.00

9.1553

93.75 KB

1.00

1000

Span_批量反序列化

109.082 μs

0.975 μs

0.253 μs

1.96

17.578

179.69 KB

1.92

1000

Binary_批量序列化

576.703 μs

15.012 μs

3.899 μs

10.38

91.797

938.71 KB

10.01

1000

Binary_批量反序列化

783.185 μs

35.201 μs

9.142 μs

14.09

102.54

1048.09 KB

11.18

4. 多线程并发(SimpleModel 序列化/反序列化)

基准(Baseline)= Span_并发序列化(同 ThreadCount 分组)

ThreadCount

方法

Mean

Error

StdDev

Ratio

Gen0

Allocated

Alloc Ratio

1

Span_并发序列化 (Baseline)

2.621 μs

0.043 μs

0.011 μs

1.00

0.1564

1.63 KB

1.00

1

Span_并发反序列化

2.624 μs

0.030 μs

0.008 μs

1.00

0.1678

1.71 KB

1.05

1

Binary_并发序列化

2.660 μs

0.023 μs

0.004 μs

1.01

0.3738

3.84 KB

2.36

1

Binary_并发反序列化

2.617 μs

0.090 μs

0.023 μs

1.00

0.3662

3.88 KB

2.38

4

Span_并发序列化 (Baseline)

2.584 μs

0.039 μs

0.010 μs

1.00

0.1984

2.07 KB

1.00

4

Span_并发反序列化

2.635 μs

0.021 μs

0.006 μs

1.02

0.2365

2.42 KB

1.17

4

Binary_并发序列化

4.896 μs

0.096 μs

0.025 μs

1.89

1.0986

11.23 KB

5.42

4

Binary_并发反序列化

5.681 μs

0.100 μs

0.026 μs

2.20

1.0986

11.36 KB

5.48

8

Span_并发序列化 (Baseline)

2.667 μs

0.110 μs

0.028 μs

1.00

0.2594

2.67 KB

1.00

8

Span_并发反序列化

2.768 μs

0.076 μs

0.020 μs

1.04

0.3204

3.36 KB

1.26

8

Binary_并发序列化

7.096 μs

0.241 μs

0.063 μs

2.66

2.0447

20.93 KB

7.82

8

Binary_并发反序列化

8.651 μs

0.188 μs

0.049 μs

3.24

2.0752

21.23 KB

7.94

20

Span_并发序列化 (Baseline)

3.726 μs

0.098 μs

0.026 μs

1.00

0.4425

4.59 KB

1.00

20

Span_并发反序列化

4.750 μs

0.121 μs

0.031 μs

1.27

0.6104

6.32 KB

1.37

20

Binary_并发序列化

12.809 μs

0.265 μs

0.069 μs

3.44

4.9133

49.94 KB

10.87

20

Binary_并发反序列化

13.206 μs

0.919 μs

0.239 μs

3.54

4.5929

46.67 KB

10.16

32

Span_并发序列化 (Baseline)

5.248 μs

0.050 μs

0.013 μs

1.00

0.6256

6.40 KB

1.00

32

Span_并发反序列化

6.777 μs

0.209 μs

0.054 μs

1.29

0.8850

9.28 KB

1.45

32

Binary_并发序列化

16.732 μs

0.138 μs

0.021 μs

3.19

7.7515

78.91 KB

12.32

32

Binary_并发反序列化

18.248 μs

0.301 μs

0.078 μs

3.48

7.8735

79.96 KB

12.49


核心指标

以下吞吐量基于单线程单次操作均值换算(ops/ms = 1,000,000 ns ÷ Mean ns)

操作

SpanSerializer(反射)

SpanSerializer(ISpanSerializable)

Binary

序列化 SimpleModel

~16,940,000 ops/s

~42,570,000 ops/s

~1,249,000 ops/s

反序列化 SimpleModel

~8,932,000 ops/s

~13,206,000 ops/s

~992,000 ops/s

批量序列化(1000条)

~17,994,000 ops/s

~1,735,000 ops/s

批量反序列化(1000条)

~9,167,000 ops/s

~1,277,000 ops/s


对比分析

纵向:多线程并发趋势

SpanSerializer 并发序列化耗时从 1 线程的 2.62 μs 增长到 32 线程的 5.25 μs,增幅约 100%,说明 Parallel.For 和线程调度本身带来了固定开销,但实际吞吐随线程增加线性扩展。

Binary 并发序列化从 1 线程 2.66 μs 增长到 32 线程 16.73 μs,增幅约 529%,主要原因是每次调用需创建 MemoryStream,高并发下 GC 压力显著放大(32 线程内存分配达 78.91 KB/op,是 SpanSerializer 的 12.3 倍)。

ThreadCount

SpanSerializer序列化

Binary序列化

差距倍数

1

2.62 μs

2.66 μs

≈1.0×

4

2.58 μs

4.90 μs

1.9×

8

2.67 μs

7.10 μs

2.7×

20

3.73 μs

12.81 μs

3.4×

32

5.25 μs

16.73 μs

3.2×

单线程下两者耗时接近(Parallel.For 本身有固定开销),4 线程以上 SpanSerializer 优势持续扩大

横向:各场景速度与内存对比

场景

SpanSerializer(反射) 速度优势

SpanSerializer 内存节省

单次序列化 Simple

13.6×

95.2%(96 B vs 2016 B)

单次序列化 Nested

11.1×

94.8%(144 B vs 2752 B)

单次反序列化 Simple

9.0×

92.3%(184 B vs 2392 B)

单次反序列化 Nested

7.9×

90.2%(328 B vs 3360 B)

批量序列化 1000 条

10.4×

90.0%(93.75 KB vs 938.71 KB)

批量反序列化 1000 条

7.2×

82.8%(179.69 KB vs 1048.09 KB)

ISpanSerializable 序列化

34.1×

100%(0 B vs 2016 B)

ISpanSerializable 反序列化

13.3×

96.3%(88 B vs 2392 B)


性能瓶颈定位

SpanSerializer 反射路径

  • 主要开销GetSchemaGetter/Setter 委托调用(已缓存编译,无热点反射)
  • 次要开销:装箱(Object? 传递值类型)——序列化每属性一次 box/unbox
  • 反序列化比序列化慢约 1.9×,因为还需 CreateInstanceSetter 写回

Binary

  • 主要开销:每次操作创建 MemoryStreamnew MemoryStream(256) ≈ 200 ns 分配)
  • 次要开销:处理器链逐 handler 匹配(foreach Handlers),每字段至少走 2~3 个 handler
  • 高并发下 GC Gen0 压力是 SpanSerializer 的 10~12 倍

ISpanSerializable 路径

  • 零反射,无装箱(直接 writer.Write(Id) 写值类型)
  • 序列化仅 23.49 ns,无任何堆分配,适用于极低延迟场景
  • 代价是需要手写 Write/Read 方法,维护成本较高

优化建议

优先级

建议

预期收益

★★★

频繁序列化的核心数据结构实现 ISpanSerializable,获得零反射+零分配

序列化再快 2.5×,内存降至 0

★★☆

SpanSerializer 内部用泛型重写 WriteValue/ReadValue,消除值类型装箱

反射路径再提速 20~40%

★★☆

反序列化路径缓存 CreateInstance 的默认构造函数委托,避免每次反射

反序列化提速 10~20%

★☆☆

Binary 场景若仍需使用,复用 MemoryStream(改用 ArrayPool + 重置 Position)

高并发内存降低 80%

★☆☆

考虑支持 Span<T> 列表/数组属性的自动序列化,减少 ISpanSerializable 手写量

扩大适用范围