依然需要用户在机器安装protoc , 而不是自动下载protoc 。由于大部分场景都是用户已经有了自定义类型和基本类型以及组合类型构成的对象(树)需要被序列化 , 因此需要将用户类型对象转换成protobuf格式 。 这里面就有较大的开发成本 , 且每种需要都需要写一遍 , 代码冗长且易出错难维护 , 同时还存在大量数据转换和拷贝开销 。 另外转换过程没有考虑实际类型 , 因此还存在类型丢失的问题 , 比如LinkedList反序列化回来变成了ArrayList 。 下面是Java的序列化代码 , 大概需要130~150行 。return build(bar).build().toByteArray();public static ProtoMessage.Bar.Builder build(Bar bar) { ProtoMessage.Bar.Builder barBuilder = ProtoMessage.Bar.newBuilder(); if (bar.f1 == null) { barBuilder.clearF1();else { barBuilder.setF1(buildFoo(bar.f1));if (bar.f2 == null) { barBuilder.clearF2();else { barBuilder.setF2(bar.f2);if (bar.f3 == null) { barBuilder.clearF3();else { for (Foo foo : bar.f3) { barBuilder.addF3(buildFoo(foo));if (bar.f4 == null) { barBuilder.clearF4();else { bar.f4.forEach( (k v) -{ ProtoMessage.Foo.Builder fooBuilder1 = ProtoMessage.Foo.newBuilder(); fooBuilder1.setF1(v.f1); v.f2.forEach(fooBuilder1::putF2); barBuilder.putF4(k fooBuilder1.build()); );if (bar.f5 == null) { barBuilder.clearF5();else { barBuilder.setF5(bar.f5);if (bar.f6 == null) { barBuilder.clearF6();else { barBuilder.setF6(bar.f6);if (bar.f7 == null) { barBuilder.clearF7();else { barBuilder.setF7(bar.f7);if (bar.f8 == null) { barBuilder.clearF8();else { barBuilder.setF8(bar.f8);if (bar.f9 == null) { barBuilder.clearF9();else { for (short i : bar.f9) { barBuilder.addF9(i);if (bar.f10 ==null) { barBuilder.clearF10();else { barBuilder.addAllF10(bar.f10);return barBuilder;public static ProtoMessage.Foo.Builder buildFoo(Foo foo) { ProtoMessage.Foo.Builder builder = ProtoMessage.Foo.newBuilder(); if (foo.f1 == null) { builder.clearF1();else { builder.setF1(foo.f1);if (foo.f2 == null) { builder.clearF2();else { foo.f2.forEach(builder::putF2);return builder;public static Foo fromFooBuilder(ProtoMessage.Foo.Builder builder) { Foo foo = new Foo(); if (builder.hasF1()) { foo.f1 = builder.getF1();foo.f2 = builder.getF2Map(); return foo;public static Bar deserializeBar(byte[
bytes) throws InvalidProtocolBufferException { Bar bar = new Bar(); ProtoMessage.Bar.Builder barBuilder = ProtoMessage.Bar.newBuilder(); barBuilder.mergeFrom(bytes); if (barBuilder.hasF1()) { bar.f1 = fromFooBuilder(barBuilder.getF1Builder());if (barBuilder.hasF2()) { bar.f2 = barBuilder.getF2();bar.f3 = barBuilder.getF3BuilderList().stream() .map(ProtoState::fromFooBuilder) .collect(Collectors.toList()); bar.f4 = new HashMap(); barBuilder.getF4Map().forEach((k v) -bar.f4.put(k fromFooBuilder(v.toBuilder()))); if (barBuilder.hasF5()) { bar.f5 = barBuilder.getF5();if (barBuilder.hasF6()) { bar.f6 = barBuilder.getF6();if (barBuilder.hasF7()) { bar.f7 = barBuilder.getF7();if (barBuilder.hasF8()) { bar.f8 = barBuilder.getF8();bar.f9 = new short[barBuilder.getF9Count()
; for (int i = 0; ibarBuilder.getF9Count(); i++) { bar.f9[i
= (short) barBuilder.getF9(i);bar.f10 = barBuilder.getF10List(); return bar; Python序列化代码:大概130~150行
GoLang序列化代码:大概130~150行
即使之前没有针对该数据的自定义类型 , 也无法将protobuf生成的class直接用在业务代码里面 。 因为protobuf生成的class并不符合面向对象设计[12
, 无法给生成的class添加行为 。 这时候就需要定义额外的wrapper , 如果自动内部有其它自定义类型 , 还需要将这些类型转换成对应的wrapper , 这进一步限制了使用的灵活性 。对比Flatbuffer
Flatbuffer与protobuf一样 , 也需要大量的学习成本和开发成本:
安装flatc编译器[13
, 对于Linux环境 , 可能还需要进行源码编译安装flatc 。定义Schema namespace io.ray.fury.benchmark.state.generated;table FBSFoo { string:string; f2_key:[string
; // flatbuffers不支持map f2_value:[int
- 中远海运特运首艘加装高压岸电系统船舶“天恩”轮通过测试
- “我们是元宇宙的领路人”|元宇宙,是QQ秀的轮回吗?
- AirPods|世界顶尖技术横空出世,全球只有我国掌握,如今轮到美国卡脖子!
- 36氪|36氪首发丨主打解腻、解渴、解乏的中国茶,「别样泡泡」完成千万级天使轮融资
- 卫星|36氪首发|专注卫星测控通信市场,「讯联科技」获得数千万A+轮融资
- 36氪首发 | 专注于研发医学营养食品,「玛士撒拉」获峰瑞资本独投的数千万元A轮融资
- 小米科技|新一轮价格战爆发?3999元的骁龙8Gen2旗舰机来了,等等党有福了
- B轮融资|曾经很火的迅雷,为什么现在不怎么火了?
- 创投圈|REVA获得a16z 2000万美金融资 WEB3.0教父再次出手
- Java|REVA获得a16z 2000万美金融资 WEB3.0教父再次出手
