C轮融资|Fury:一个基于JIT动态编译的高性能多语言原生序列化框架( 九 )


依然需要用户在机器安装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