解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
|
# SpanSerializer vs Binary åºåˆ—化性能测试
## 性能概览
`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)|
---
## 性能瓶颈定ä½
### æ ¸å¿ƒç“¶é¢ˆç‚¹æ€»è§ˆ
| 优先级 | 瓶颈 | ä¼˜åŒ–æ”¶ç›Šå æ¯” | 当å‰å¼€é”€ | 优化åŽé¢„ä¼° | 内å˜èŠ‚çœ |
|--------|------|------------|---------|-----------|---------|
| P0 | Binary MemoryStream æ¯æ¬¡é‡å»º | ~35% | 800 ns / 2,016 B(Simple åºåˆ—化) | è¿ç§»è‡³ SpanSerializer:59 ns / 96 B | **95.2%(1,920 B/op)** |
| P0 | Binary 处ç†å™¨é“¾é€ handler åŒ¹é… | ~25% | æ¯å—段 2-3 handler é历,~400 ns 处ç†å™¨å¼€é”€ | è¿ç§»è‡³ SpanSerializer 消除 | **100%** |
| P1 | SpanSerializer å射路径值类型装箱 | ~20% | æ¯å±žæ€§ 1 次 box/unbox,ååºåˆ—化 112 ns(vs ISpanSerializable 76 ns) | 泛型é‡å†™æ¶ˆé™¤è£…箱:~80-90 ns | **30-40%** |
| P1 | SpanSerializer CreateInstance åå°„ | ~10% | ååºåˆ—化 112 nsï¼ˆå«æž„é€ ï¼‰ï¼Œæ¯”åºåˆ—化 59 ns æ…¢ 1.9x | ç¼“å˜æž„é€ å‡½æ•°å§”æ‰˜ï¼š~90-100 ns | **10-20%** |
| P2 | Binary é«˜å¹¶å‘ GC 压力放大 | ~5% | 32T åºåˆ—化 78.91 KB/op(SpanSerializer ä»… 6.40 KB) | è¿ç§»è‡³ SpanSerializer | **91.9%** |
| P3 | SpanSerializer ååºåˆ—化 String åˆ†é… | ~5% | ååºåˆ—化 184 B/opï¼ˆå« String å †åˆ†é…) | 使用 Span<Char> é›¶æ‹·è´ï¼š88 B/op | **52.2%** |
### 关键内å˜ä¼˜åŒ–æ–¹å‘
| 优先级 | ä¼˜åŒ–æ–¹å‘ | 当å‰åˆ†é… | 优化åŽé¢„ä¼° | èŠ‚çœæ¯”例 | 实施方案 |
|--------|---------|---------|-----------|---------|---------|
| P0 | Binary → SpanSerializer è¿ç§» | 2,016 B/op(åºåˆ—化) | 96 B/op | **95.2%** | 频ç¹åºåˆ—化的数æ®ç»“构改用 SpanSerializer |
| P0 | Binary → ISpanSerializable è¿ç§» | 2,016 B/op(åºåˆ—化) | 0 B/op | **100%** | æ ¸å¿ƒæ•°æ®ç»“构实现 `ISpanSerializable` æŽ¥å£ |
| P1 | å射路径值类型装箱消除 | 96 B/op → å«è£…箱开销 | ~60 B/op | **~37%** | 泛型é‡å†™ `WriteValue`/`ReadValue` |
| P2 | Binary å¹¶å‘场景 MemoryStream å¤ç”¨ | 78.91 KB/op(32T) | ~10 KB/op | **87%** | `ArrayPool` + é‡ç½® Position |
### 瓶颈 1(P0):Binary åºåˆ—化器 MemoryStream é‡å»º
- **现象**:Binary SimpleModel åºåˆ—化 800.83 ns / 2,016 B,是 SpanSerializer(59.03 ns / 96 B)的 **13.6x æ…¢ã€21x 内å˜**
- **æ ¹æº**ï¼šæ¯æ¬¡ `Binary.Write` 创建 `new MemoryStream(256)`,åˆå§‹åˆ†é… 256 å—节数组 + MemoryStream 对象(~200 ns)
- **å½±å“**ï¼šé«˜å¹¶å‘ 32 线程下内å˜è¾¾ 78.91 KB/op,GC Gen0 压力是 SpanSerializer çš„ 12.3 å€
| å¼€é”€æ¥æº | å æ¯”ä¼°ç®— | 耗时估算 | 说明 |
|---------|---------|---------|------|
| MemoryStream æž„é€ + æ•°ç»„åˆ†é… | ~25% | ~200 ns | `new MemoryStream(256)` å †åˆ†é… |
| 处ç†å™¨é“¾é历 | ~50% | ~400 ns | `foreach Handlers` é€ handler 匹é…å—æ®µ |
| 缓冲区扩容 + æ•°æ®å†™å…¥ | ~25% | ~200 ns | å—æ®µæ•°æ®å†™å…¥ + å¯èƒ½çš„æ•°ç»„扩容 |
- **优化方案**:将频ç¹åºåˆ—åŒ–çš„æ ¸å¿ƒæ•°æ®ç»“æž„è¿ç§»è‡³ SpanSerializer
- **预期收益**:速度æå‡ **13.6x**,内å˜é™ä½Ž **95.2%**
### 瓶颈 2(P1):SpanSerializer å射路径值类型装箱
- **现象**:ååºåˆ—化 111.96 ns / 184 B,比 ISpanSerializable(75.72 ns / 88 B)慢 **1.5x**
- **æ ¹æº**:`Getter/Setter` 委托通过 `Object?` ä¼ é€’å€¼ç±»åž‹ï¼Œæ¯å±žæ€§äº§ç”Ÿä¸€æ¬¡ box/unbox
- **å½±å“**:5 å—æ®µçš„ SimpleModel åºåˆ—化时产生 5 次装箱
| å¼€é”€æ¥æº | å æ¯”ä¼°ç®— | 耗时估算 | 说明 |
|---------|---------|---------|------|
| 装箱(Object? ä¼ é€’å€¼ç±»åž‹ï¼‰ | ~30% | ~18 ns | 5 å—æ®µ × ~3.5 ns/次装箱 |
| Getter 委托调用 | ~40% | ~24 ns | 5 å—æ®µ × 编译缓å˜å§”托调用 |
| ç±»åž‹åˆ¤æ– + Span 写入 | ~30% | ~17 ns | GetSchema ç±»åž‹åŒ¹é… + writer.Write |
- **优化方案**:泛型é‡å†™ `WriteValue<T>`/`ReadValue<T>`,消除值类型装箱
- **预期收益**:åå°„è·¯å¾„å†æé€Ÿ **20-40%**
### 瓶颈 3(P1):SpanSerializer ååºåˆ—化 CreateInstance
- **现象**:ååºåˆ—化(111.96 ns)比åºåˆ—化(59.03 ns)慢 **1.9x**
- **æ ¹æº**:需 `CreateInstance` æž„é€ æ–°å¯¹è±¡ + `Setter` å†™å›žå—æ®µï¼Œæ¯”åºåˆ—化多一æ¥å¯¹è±¡åˆ›å»º
- **å½±å“**ï¼šæ¯æ¬¡ååºåˆ—化é¢å¤– ~10-20 ns 用于对象构é€
- **优化方案**:缓å˜é»˜è®¤æž„é€ å‡½æ•°çš„å§”æ‰˜ï¼ˆ`Activator.CreateInstance` → 编译 `Expression.New`)
- **预期收益**:ååºåˆ—化æé€Ÿ **10-20%**
### SpanSerializer å射路径 vs ISpanSerializable 对比
| 维度 | å射路径 | ISpanSerializable | å·®è· |
|------|---------|-------------------|------|
| åºåˆ—化耗时 | 59.03 ns | 23.49 ns | 2.5x |
| ååºåˆ—化耗时 | 111.96 ns | 75.72 ns | 1.5x |
| åºåˆ—åŒ–åˆ†é… | 96 B | 0 B | ∞ |
| ååºåˆ—åŒ–åˆ†é… | 184 B | 88 B | 2.1x |
| ç»´æŠ¤æˆæœ¬ | 零(自动) | 高(手写 Write/Read) | — |
---
## 优化建议
| 优先级 | æ–¹å‘ | 预期收益 | 实施方案 |
|--------|------|---------|---------|
| P0 ★★★ | **æ ¸å¿ƒæ•°æ®ç»“构实现 `ISpanSerializable`** | åºåˆ—化å†å¿« **2.5x**,内å˜é™è‡³ **0 B** | 频ç¹åºåˆ—化的 RPC 消æ¯ä½“实现接å£ï¼ŒèŽ·å¾—é›¶åå°„+零分é…路径 |
| P1 ★★☆ | **泛型é‡å†™ `WriteValue`/`ReadValue`** | åå°„è·¯å¾„å†æé€Ÿ **20-40%**,消除值类型装箱 | 用 `WriteValue<T>` 替代 `WriteValue(Object?)`,é¿å…æ¯å±žæ€§ box/unbox |
| P1 ★★☆ | **ç¼“å˜ `CreateInstance` æž„é€ å‡½æ•°å§”æ‰˜** | ååºåˆ—化æé€Ÿ **10-20%** | 编译 `Expression.New` 并缓å˜ï¼Œé¿å…æ¯æ¬¡åå°„æž„é€ |
| P2 ★☆☆ | **Binary 场景å¤ç”¨ MemoryStream** | 高并å‘内å˜é™ä½Ž **80%** | `ArrayPool` + é‡ç½® Position æ›¿ä»£æ¯æ¬¡ `new MemoryStream(256)` |
| P3 ★☆☆ | **æ”¯æŒ `Span<T>` 属性自动åºåˆ—化** | 扩大 ISpanSerializable 适用范围,å‡å°‘æ‰‹å†™é‡ | 列表/数组属性的自动 Span åºåˆ—åŒ–æ”¯æŒ |
|