内容简介:使用 flatbuffers 已经有相当长的一段时间了.在几个商用项目中, flatbuffers 也因快速的反序列化而带来性能上的不少提升.flatbuffers 尤其适合传输小块数据, 一次序列化, 多个地方进行反序列化.
使用 flatbuffers 已经有相当长的一段时间了.
在几个商用项目中, flatbuffers 也因快速的反序列化而带来性能上的不少提升.
flatbuffers 尤其适合传输小块数据, 一次序列化, 多个地方进行反序列化.
但 go 的 flatbuffers 有一些小遗憾:
- go flatbuffers 功能支持, 滞后于 c++ 版, Go 代码库也很久没有更新了. 相比 c ++ , go 版本缺少一些功能. 如 vector of unions , 在 unions 中包含 struct / strings . ( 注: go 版本的 flatbuffers 在 unions 中只能包含 table )
- 缺少 verifier 验证器 ( 这是我需要的)
- go flatbuffers 序列化的速度, 慢于 gogo protobuf. flatbuffers 序列化消耗的时间, 大约是 gogo protobuf 的两倍.
- go flatbuffers 不支持 go module. 尤其是自动生成的 go 代码存在相互引用时的 import 并不友好.
- go flatbuffers 的序列化代码不太优雅, 不太符合 go 的习惯风格
在这样情况下, 我起了改进 go flatbuffers 的念头.
flatbuffers 的编译器, 是 c++ 写的. 我已经很多年没有用过 c++ 开发了. 对我来说, 这可能是一次有趣的探险历程.
1. 我对 go flatbuffers 的折腾
刚开始, 我写一个 flatbuffers verifier , 本地验证通过后, 我向 google flatbuffers 发了一个 PR. 结果被建议我重读一下 flatbuffers 的设计规范文档. 嗯哼, 这就开始有趣了.
在接下来的两周左右, 我边读 flatbuffers 的关键规范文档 ( 见附录参考列表) , 边写了一个全新的序列化生成器 ( flatbuffers builder ) .
我拆分了flatbuffers 的 memory block , 采用 goroutine 并发处理各个独立的 memory block 转化为二进制序列数据, 最后进行合并/排序/优化. 当这个手写序列化器看起来可以工作时, 我发现, 需要把这些手写代码嵌入 flatbuffers 编译器中, 支持自动代码生成, 我遇到了一个小难题. 我几乎忘记如何写 C++ 了.
为此, 我重读了 Effective C++ 这样的几本册子, 随书写几行代码跑跑. 一周之后, 重新熟悉 C++ , 意外收获是对 go 的内存管理有了进一步的认识.
如何让 go flatbuffers 序列化更快, 我还在尝试中.
而熟悉了 C++ 后, 我先让 go flatbuffers API 变得清晰简单, 易用一些.
2. 移植 C++ 有用功能, 支持 vector of unions.
union 是 flatbuffers 中很有趣也很有用的一个功能, 当然, struct 也很有用. go flatbuffers 中, union 只支持 table , 并且不支持 union array ( 被称为 vector of unions ) , 先加上这个
IDL
union Character { MuLan: Attacker, // table, 相当于 protobuf 中的 message Rapunzel, // struct , 与 c++ 的 struct 相当 Belle: BookReader, BookFan: BookReader, Other: string, // string Unused: string } table Movie { main_character: Character; // 单一 union 字段 characters: [Character]; // vector of unions } 复制代码
3. 支持 go module via Attribute ( 在 IDL 定义中 ).
每一个 fbs IDL 定义文件都支持各自的 module , 格式像这样: "go_module:github.com/tsingson/flatbuffers-sample/go-example/";
weapons.fbs
namespace weapons; attribute "go_module:github.com/tsingson/flatbuffers-sample/samplesNew/"; table Gun { damage:short; bool:bool; name:string; names:[string]; } 复制代码
monster.fbs
include "../weapons.fbs"; namespace Mygame.Example; attribute "go_module:github.com/tsingson/flatbuffers-sample/go-example/"; enum Color:byte { Red = 0, Green, Blue = 2 } union Equipment { MuLan: Weapon, Weapon, Gun:weapons.Gun, SpaceShip, Other: string } // Optionally add more tables. ...... 复制代码
生成的 go 代码
package Example import ( "strconv" flatbuffers "github.com/google/flatbuffers/go" weapons "github.com/tsingson/flatbuffers-sample/samplesNew/weapons" /// 嗯哼! ) type Equipment byte .......... 复制代码
4. 增加一些清晰易用的 API /生成代码.
weaponsOffset := flatbuffers.UOffsetT(0) if t.Weapons != nil { weaponsLength := len(t.Weapons) weaponsOffsets := make([]flatbuffers.UOffsetT, weaponsLength) for j := weaponsLength - 1; j >= 0; j-- { weaponsOffsets[j] = t.Weapons[j].Pack(builder) } MonsterStartWeaponsVector(builder, weaponsLength) //////// start for j := weaponsLength - 1; j >= 0; j-- { builder.PrependUOffsetT(weaponsOffsets[j]) } weaponsOffset = MonsterEndWeaponsVector(builder, weaponsLength) /////// end } 复制代码
shortcut for []strings vector
// native object Names []string // builder namesOffset := builder.StringsVector( t.Names...) 复制代码
getter for vector of unions
func (rcv *Movie) Characters(j int, obj *flatbuffers.Table) bool { o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) if o != 0 { a := rcv._tab.Vector(o) obj.Pos = a + flatbuffers.UOffsetT(j*4) obj.Bytes = rcv._tab.Bytes return true } return false } 复制代码
so get struct or table
// GetStructVectorAsBookReader shortcut to access struct in vector of unions func GetStructVectorAsBookReader(table *flatbuffers.Table) *BookReader { n := flatbuffers.GetUOffsetT(table.Bytes[table.Pos:]) x := &BookReader{} x.Init(table.Bytes, n+ table.Pos) return x } // GetStructAsBookReader shortcut to access struct in single union field func GetStructAsBookReader(table *flatbuffers.Table) *BookReader { x := &BookReader{} x.Init(table.Bytes, table.Pos) return x } 复制代码
for object-api , comments in generated code to make it clear
// UnPack use for single union field func (rcv Character) UnPack(table flatbuffers.Table) *CharacterT { switch rcv { case CharacterMuLan: x := GetTableAsAttacker(&table) return &CharacterT{ Type: CharacterMuLan, Value: x.UnPack() } ............. // UnPackVector use for vector of unions func (rcv Character) UnPackVector(table flatbuffers.Table) *CharacterT { switch rcv { case CharacterMuLan: x := GetTableVectorAsAttacker(&table) return &CharacterT{ Type: CharacterMuLan, Value: x.UnPack() } case CharacterRapunzel: ......... 复制代码
或许, 稍后更多, 让 Go flatbuffers ...... 更好用.
5. happy hacking....... 折腾继续中
本文持续有更新...........
.
.
本文首发于 GolangChina , 在此 gocn.vip/topics/1022…
祝安康愉快!
_
_
关于我
网名 tsingson (三明智)
原 ustarcom IPTV/OTT 事业部播控产品线技术架构湿/解决方案工程湿角色(8年), 自由职业者,
喜欢音乐(口琴,是第三/四/五届广东国际口琴嘉年华的主策划人之一), 摄影与越野,
喜欢 golang 语言 (商用项目中主要用 postgres + golang )
tsingson ( 三明智 ) 于深圳南山. 小罗号口琴音乐中心 2020/04/09
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 为什么说 LINQ 要胜过 SQL
- 中科创达副总裁孙力:AI视觉仍在路上,平台需求胜过算法
- 未雨绸缪胜过事后诸葛亮!你需要一款系统级应急接管与快速恢复产品!
- FreeBSD 13.0-RC1 发布:改进 TCP 性能、修复和改进 SCTP
- Lanai-UI 改进后发布,AdminLTE 改进后的脚手架
- 敏捷开发的持续改进
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
区块链与人工智能:数字经济新时代
高航、俞学劢、王毛路 / 电子工业出版社 / 2018-7-23 / 80
《区块链与人工智能》是畅销书《区块链与新经济:数字货币2.0时代》全新修订升级版。本书是市场上为数不多的系统阐述区块链、人工智能技术与产业的入门级系统教程。从比特币到各类数字货币(代币),从基础原理到应用探讨,全景式呈现区块链与人工智能的发展脉络,既有历史的厚重感也有科技的未来感。本书的另一个亮点是系统整理了区块链创业地图,是一本关于区块链创业、应用、媒体的学习指南,以太坊创始人Vitalik专门......一起来看看 《区块链与人工智能:数字经济新时代》 这本书的介绍吧!