像从未有过的那样解析 Protobuf · mcyoung

主要观点:作者曾从事与高性能 Protobuf 相关项目,现介绍新库hyperpb,它将 UPB 的优化带到 Go 中且有新优化,在各基准测试中远超其他 Go Protobuf 解析器,完全运行时动态且比 Protobuf Go 生成代码和vtprotobuf更快;解释了重新发明 UPB 的原因,如 Go 的 C FFI 不佳,Go 有独特品质适合写 Protobuf 解释器等;介绍hyperpb的 API 简单,通过hyperpb.Compile*函数编译消息描述符得到*hyperpb.MessageType用于反射等操作,还有性能调优旋钮;详细阐述hyperpb的核心实现部分,包括tdp相关定义、解析器 VM 的设计及优化,如利用 Go 的 ABI 最大程度减少栈溢出、特殊的热/冷区域划分、零拷贝字符串、重复预加载、映射优化、 arena 重用、oneof 联合等优化措施,最后总结hyperpb令人兴奋,仍有很多可优化之处,鼓励贡献和继续探索。

关键信息:

  • hyperpb:新库,将 UPB 优化带到 Go 中,性能远超其他 Go Protobuf 解析器。
  • 重新发明 UPB 的原因:Go 的 C FFI 差,Go 有独特品质适合写 Protobuf 解释器等。
  • hyperpb的 API:简单,通过hyperpb.Compile*函数编译消息描述符,有性能调优旋钮。
  • hyperpb的核心实现:tdp相关定义、解析器 VM 的设计及优化,如热/冷区域划分、零拷贝等。
  • 其他优化措施:零拷贝字符串、重复预加载、映射优化、arena 重用、oneof 联合等。

重要细节:

  • UPB 是解析 Protobuf 消息的小 C 内核,完全动态。
  • hyperpb的 API 可缓存编译步骤,有主 API 和性能调优相关部分。
  • tdp.Type包含消息类型的动态大小等信息,tdp.FieldParser包含字段解析相关信息,通过字段调度避免查找下一个字段的工作。
  • 解析器 VM 设计利用 Go 的 ABI 减少栈溢出,核心循环通过ifgoto实现,虚拟函数调用在该场景下更快。
  • 零拷贝字符串用于stringbytes及 packed 字段,varint 字段也可零拷贝;重复预加载根据 PGO 记录预加载重复字段;映射优化使用特定哈希和 arena 管理内存;arena 重用可避免 Go 分配器的开销,但需注意内存安全;oneof 联合在 Go 中通过接口实现,hyperpb的 arena 设计可实现真正的联合。
阅读 163
0 条评论