mirror of
https://github.com/deepseek-ai/3FS.git
synced 2026-11-05 00:47:47 +00:00
[GH-ISSUE #313] [optimize serialize performance]简化序列化/反序列化代码,消除宏,提升性能 #190
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/3FS#190
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @qicosmos on GitHub (Jul 16, 2025).
Original GitHub issue: https://github.com/deepseek-ai/3FS/issues/313
动机
目前3fs::serde的序列化/反序列化基于宏实现的编译期反射实现的,这种写法在新版本编译器中是可以大幅简化的,yalantinglibs的序列化库struct_pack 正是基于新的编译期反射实现思路实现的,大幅简化了序列化/反序列化的实现并且比3fs::serde的性能高了将近一个数量级,建议使用struct_pack 来替换3fs::serde来简化代码和提升性能,代码改造的代价也不大。
比较
序列化对象定义的比较
3fs::serde 定义序列化结构体:
struct_pack 定义序列化结构体:
都是同样内存布局的结构体,struct_pack的定义不需要任何宏,代码更简洁。
性能比较
对person对象做10万次序列化反序列化看耗时.
测试1
person的定义,测试长字符串和大数字:
benchmark结果:
3fs 序列化耗时:11699562 ns
struct_pack序列化耗时:1210753 ns
3fs 反序列化耗时:3006874 ns
struct_pack反序列化耗时:1520934 ns
序列化速度struct_pack 是3fs的9.6倍;反序列化速度struct_pack是3fs 的1.9倍
测试2
person的定义, 测试短字符串和小数字:
benchmark结果:
3fs 序列化耗时:4544700 ns
struct_pack序列化耗时:524934 ns
3fs 反序列化耗时:2343792 ns
struct_pack反序列化耗时:747060 ns
序列化速度struct_pack 是3fs的8.7倍;反序列化速度struct_pack是3fs 的3.1倍
测试3
将person定义中的std::string 类型改成std::string_view 类型,测试零拷贝场景下反序列化的速度。
person初始化同上,两次测试结果如下。
长字符串和大数字:
3fs 反序列化耗时:2505920 ns
struct_pack反序列化耗时:580043 ns
反序列化速度struct_pack是3fs 的4.3倍
短字符串和小数字:
3fs 反序列化耗时:2372563 ns
struct_pack反序列化耗时:381896 ns
反序列化速度struct_pack是3fs 的6.2倍
benchmark 代码
替换序列化库的工作量
把宏定义去掉,定义成普通结构体即可;
2.序列化和反序列化接口稍作修改即可
3.json 部分的改造
可以使用struct_json去将对象序列化成json字符串,对象还是一个普通的c++结构体即可,这个结构体即可以转换为struct_pack格式也可以转换为json或者xml格式,类似于:
@SF-Zhou commented on GitHub (Jul 17, 2025):
Thank you for your attention.
3fs::serdeprioritizes reducing serialized data size (even at an additional cost) to minimize network transmission time. You can verify the actual serialized length.out0.bytes().reset()releases the internal buffer, whilebuffer.clear()does not, making this comparison unfair.std::stringbenefits from SSO (Small String Optimization), which gives it an advantage at very small serialized lengths.@qicosmos commented on GitHub (Jul 17, 2025):
谢谢回复。
第一点我就不做评论了。
第二点我其实想说的是现在的实现方法比较繁琐复杂,可以简化实现,至少可以把宏消除掉。
第三点我测了,短字符串和长字符串,序列化长度二者是相当的:长字符串(1024)时3fs的size是1044,struct_pack是1047,相差3个字节而已;短字符串(sso),3fs是21字节,struct_pack是24字节,相差3字节。
第四点,我不知道怎么去优化这个buffer,怎么去复用这个buffer呢?你可以给一个建议。
关于sso,我实际上测了非sso的场景(字符串长度1024)。我希望可以把内存的开销完全避免掉,只测序列化反序列化的开销。
@qicosmos commented on GitHub (Jul 17, 2025):
另外,我理解现在的序列化其实是没法做类型安全校验的对吧,非法二进制可能也会成功反序列化。struct_pack是做了类型校验的,不会允许这种情况发生。anyway,只是提一个建议。
@acking-you commented on GitHub (Jul 25, 2025):
我感觉如果扣这个的话,就没必要自己实现了,交给比较活跃的第三方库即可,同样基于编译期反射的序列化库实现,我可能会选择直接用 glaze ,不过这个得开 cpp23,