cpp-serializers简介
cpp-serializers 是一个专注于 C++ 序列化库性能基准测试
https://github.com/thekvs/cpp-serializers
在嵌入式系统、高性能计算、分布式通信等场景中,序列化方案的选择直接影响系统的吞吐量、内存占用和通信效率,而本项目通过对 9 种主流序列化库进行横向对比,揭示了不同编码方案在数据体积和序列化速度上的显著差异,为工程师提供了基于实测数据的决策依据。
核心特性
自动化依赖管理通过 CMake ExternalProject 模块自动下载并编译所有序列化库(Boost、Thrift、Protobuf 等),开发者无需手动配置复杂的环境依赖,只需执行标准构建流程即可获得完整的测试环境。
灵活的测试控制支持通过命令行参数精确指定测试迭代次数、选择特定序列化库、输出 CSV 格式数据,便于集成到 CI/CD 流程或批量对比实验中。
统一的测试数据使用预定义的 300+ 个 int64 整数和 100 个固定长度字符串作为测试负载,确保所有序列化库在相同的数据条件下竞争,消除数据差异带来的偏差。
多维度的性能指标同时测量序列化后的数据体积和序列化+反序列化的总耗时,帮助开发者根据实际场景权衡空间效率和时间效率。
项目架构概览
项目采用清晰的分层架构设计,将测试框架、数据定义、序列化实现和构建系统分离,既保证了代码的可维护性,也方便扩展新的序列化库。以下架构图展示了各模块之间的关系和数据流转过程:
测试框架层负责协调整个基准测试流程,测试数据层提供标准化的输入数据,序列化实现层包含各种序列化库的具体实现,IDL 定义层存储各序列化方案的接口定义文件。箭头表示数据流转方向,虚线表示代码生成关系。
项目目录结构
项目的目录组织遵循职责分离原则,每个子目录对应一种序列化库的实现或工具链,便于开发者定位特定库的源代码和配置文件。根目录下的 IDL 文件定义了统一的测试数据结构,各序列化库必须实现相同的语义才能保证测试的公平性:
cpp-serializers/
├── benchmark.cpp # 基准测试主程序
├── data.hpp # 测试数据定义
├── CMakeLists.txt # 构建系统配置
├── test.proto # Protobuf IDL定义
├── test.thrift # Thrift IDL定义
├── test.fbs # FlatBuffers Schema定义
├── test.capnp # Cap'n Proto Schema定义
├── protobuf/ # Protobuf生成代码
│ ├── test.pb.cc
│ └── test.pb.h
├── thrift/ # Thrift生成代码
│ └── gen-cpp/
├── flatbuffers/ # FlatBuffers生成代码
│ └── test_generated.h
├── capnproto/ # Cap'n Proto生成代码
│ ├── test.capnp.c++
│ └── test.capnp.h
├── boost/ # Boost序列化实现
│ ├── record.hpp
│ └── record.cpp
├── cereal/ # Cereal序列化实现
│ ├── record.hpp
│ └── record.cpp
├── yas/ # YAS序列化实现
│ ├── record.hpp
│ └── record.cpp
├── msgpack/ # Msgpack序列化实现
│ └── record.hpp
├── avro/ # Avro序列化实现
│ └── record.hpp
└── images/ # 性能测试结果图表
├── size.png
├── time.png
└── time2.png
目录说明: 带 test.* 前缀的文件是各序列化库的接口定义语言文件,用于生成类型安全的序列化代码。各库的实现目录中,header-only 库(如 YAS、Msgpack)仅需 .hpp 文件,而需要编译的库(如 Boost、Cereal)则包含 .cpp 实现文件。
支持的序列化器列表:
| 序列化器名称 | 类别 | 主要特点 | 典型应用场景 |
|---|---|---|---|
thrift-binary |
TLV编码 | Apache Thrift二进制协议,跨语言支持强 | 分布式服务通信 |
thrift-compact |
TLV编码 | Thrift紧凑协议,数据体积小 | 带宽受限环境 |
protobuf |
TLV编码 | Google Protocol Buffers,生态成熟 | 微服务通信、数据存储 |
boost |
定长二进制 | Boost.Serialization,C++原生支持 | 单语言C++项目 |
msgpack |
二进制JSON | Msgpack格式,类似JSON但更紧凑 | API响应序列化 |
cereal |
定长二进制 | Header-only库,易于集成 | 轻量级序列化需求 |
avro |
Schema驱动 | Apache Avro,Schema演化支持好 | 大数据生态系统 |
capnproto |
零拷贝 | Cap'n Proto,无序列化开销 | 高性能RPC框架 |
flatbuffers |
零拷贝 | Google FlatBuffers,向前兼容性好 | 游戏开发、移动应用 |
yas |
定长二进制 | YAS库,极致性能优化 | 性能敏感场景 |
yas-compact |
定长二进制 | YAS紧凑模式,平衡速度与体积 | 存储空间受限场景 |
支持的序列化方案对比
项目当前支持 9 种主流序列化库,根据其编码原理可以分为四大类:TLV 编码方案、定长二进制方案、零拷贝方案和其他方案。下表从数据体积、序列化速度、易用性和典型应用场景四个维度进行对比,帮助开发者快速定位适合自己需求的序列化库:
| 序列化库 | 编码类型 | 数据体积(Bytes) | 耗时(ms) | 典型应用场景 |
|---|---|---|---|---|
| YAS | 定长二进制 | 17416 | 302 | 极致性能场景 |
| YAS-compact | 定长+压缩 | 13321 | 2063 | 带宽受限场景 |
| Cereal | 定长二进制 | 17416 | 1052 | 快速原型开发 |
| Thrift-binary | TLV编码 | 17017 | 1190 | RPC微服务通信 |
| Thrift-compact | TLV+压缩 | 13378 | 3474 | 跨语言通信 |
| Boost | 定长二进制 | 17470 | 1195 | 已有Boost生态 |
| Protobuf | TLV编码 | 16116 | 2312 | 跨平台数据交换 |
| Msgpack | 动态编码 | 13402 | 2560 | JSON兼容场景 |
| Avro | Schema编码 | 16384 | 4488 | 大数据生态系统 |
| Cap'n Proto | 零拷贝 | 17768 | 401 | 实时数据处理 |
| FlatBuffers | 零拷贝 | 17632 | 492 | 游戏引擎/移动端 |
表注: 耗时数据基于 100 万次序列化+反序列化测试,测试环境为 Intel Core i7 处理器。体积越小越好,耗时越短越好。易用性评分综合考虑了学习曲线、文档质量、调试便利性等因素。零拷贝方案的耗时包括 build/serialize/deserialize 完整周期。
典型使用场景
场景 1:完整基准测试
测试所有序列化库,每个库执行 100,000 次序列化/反序列化操作:
./benchmark -i 100000
输出示例:
Serializer: thrift-binary
Version : 0.12.0
Iterations: 100000
Size : 17017 bytes
Time : 1190 milliseconds
Serializer: protobuf
Version : 3.7.0
Iterations: 100000
Size : 16116 bytes
Time : 2312 milliseconds
...
场景 2:定向对比测试
仅对比 Protobuf 和 YAS 两个库的性能:
./benchmark -i 100000 -s protobuf,yas
场景 3:CSV 格式输出
生成适合导入电子表格或数据分析工具的 CSV 格式结果:
./benchmark -i 100000 -c > results.csv
CSV 文件格式:
serializer,version,iterations,size,time
thrift-binary,0.12.0,100000,17017,1190
protobuf,3.7.0,100000,16116,2312
...
一份打通“应用→驱动”的Linux底层修炼指南!
216