解决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)|
---
## 性能瓶颈定ä½
### SpanSerializer å射路径
- **主è¦å¼€é”€**:`GetSchema` → `Getter/Setter` 委托调用(已缓å˜ç¼–è¯‘ï¼Œæ— çƒç‚¹å射)
- **次è¦å¼€é”€**:装箱(`Object?` ä¼ é€’å€¼ç±»åž‹ï¼‰â€”â€”åºåˆ—化æ¯å±žæ€§ä¸€æ¬¡ box/unbox
- ååºåˆ—化比åºåˆ—化慢约 **1.9×**ï¼Œå› ä¸ºè¿˜éœ€ `CreateInstance` å’Œ `Setter` 写回
### Binary
- **主è¦å¼€é”€**ï¼šæ¯æ¬¡æ“作创建 `MemoryStream`(`new 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` æ‰‹å†™é‡ | 扩大适用范围 |
|