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


.f1 foo_row.f4[200000
.f2[5
)print(f\"end: {datetime.datetime.now()\")binary = pickle.dumps(foo)print(f\"pickle start: {datetime.datetime.now()\")new_foo = pickle.loads(binary)print(new_foo.f2[100000
new_foo.f4[100000
.f1 new_foo.f4[200000
.f2[5
)print(f\"pickle end: {datetime.datetime.now()\") Java示例
public class Bar { String f1; ListLongf2;public class Foo { int f1; ListIntegerf2; MapString Integerf3; ListBarf4;EncoderFooencoder = Encoders.rowEncoder(Foo.class);BinaryRow binaryRow = encoder.toRow(foo); // 该数据可以被Python零拷贝解析Foo newFoo = encoder.fromRow(binaryRow); // 可以是来自python序列化的数据BinaryArray binaryArray2 = binaryRow.getArray(1); // 零拷贝读取ListIntegerf2字段BinaryArray binaryArray4 = binaryRow.getArray(4); // 零拷贝读取ListBarf4字段BinaryRow barStruct = binaryArray4.getStruct(10);// 零拷贝读取读取ListBarf4第11个元素数据// 零拷贝读取读取ListBarf4第11个元素数据的f2字段的第6个元素long aLong = barStruct.getArray(1).getLong(5);EncoderBarbarEncoder = Encoders.rowEncoder(Bar.class);// 部分反序列化对象Bar newBar = barEncoder.fromRow(barStruct);Bar newBar2 = barEncoder.fromRow(binaryArray4.getStruct(20));// 对象创建示例:// Foo foo = new Foo();// foo.f1 = 10;// foo.f2 = IntStream.range(0 1000000).boxed().collect(Collectors.toList());// foo.f3 = IntStream.range(0 1000000).boxed().collect(Collectors.toMap(i -\"k\"+i i-i));// ListBarbars = new ArrayList(1000000);// for (int i = 0; i1000000; i++) {// Bar bar = new Bar();// bar.f1 = \"s\"+i;// bar.f2 = LongStream.range(0 10).boxed().collect(Collectors.toList());// bars.add(bar);// // foo.f4 = bars; 自动转换Arrow
Fury Format支持自动与Arrow列存互转 。
Python示例:
import pyfuryencoder = pyfury.encoder(Foo)encoder.to_arrow_record_batch([foo
* 10000)encoder.to_arrow_table([foo
* 10000) C++示例:
std::shared_ptrArrowWriterarrow_writer;EXPECT_TRUE( ArrowWriter::Make(schema ::arrow::default_memory_pool()arrow_writer) .ok());for (autorow : rows) { EXPECT_TRUE(arrow_writer-Write(row).ok());std::shared_ptr::arrow::RecordBatchrecord_batch;EXPECT_TRUE(arrow_writer-Finish(record_batch).ok());EXPECT_TRUE(record_batch-Validate().ok());EXPECT_EQ(record_batch-num_columns() schema-num_fields());EXPECT_EQ(record_batch-num_rows() row_nums); Java示例:
Schema schema = TypeInference.inferSchema(BeanA.class);ArrowWriter arrowWriter = ArrowUtils.createArrowWriter(schema);EncoderBeanAencoder = Encoders.rowEncoder(BeanA.class);for (int i = 0; i10; i++) { BeanA beanA = BeanA.createBeanA(2); arrowWriter.write(encoder.toRow(beanA));return arrowWriter.finishAsRecordBatch(); 对比其它序列化框架 跟其它框架的对比将分为功能、性能和易用性三个维度 , 每个维度上Fury都有比较显著的优势 。
功能比较
这里从10个维度将Fury跟别的框架进行对比 , 每个维度的含义分别为:
多语言/跨语言:是否支持多种语言以及是否支持跨语言序列化 自动序列化:是否需要写大量序列化代码 , 还是可以完全自动话 是否需要schema编译:是否需要编写schema IDL文件 , 并编译schema生成代码 自定义类型:是否支持自定义类型 , 即POJO/DataClass/Struct等 非自定义类型:是否支持非自定义类型 , 即是否支持直接序列化基本类型、数组、List、Map等 , 还是需要将这些类型包装到自定义类型内部才能进行序列化 引用/循环引用:对于指向同一个对象的两份引用 , 是否只会序列化数据一次;对于循环引用 , 是否能够进行序列化而不是出现递归报错 多态子类型:对于List/Map的多个子类型如ArrayList/LinkedList/ImmutableList , HashMap/LinkedHashMap等 , 反序列化是否能够得到相同的类型 , 还是会变成ArrayList和HashMap 反序列化是否需要传入类型:即是否需要在反序列化时需要提前知道数据对应的类型 。 如果需要的话则灵活性和易用性会受到限制 , 而且传入的类型不正确的话反序列化可能会crash 部分反序列化/随机读写:反序列化是否可以只读取部分字段或者嵌套的部分字段 , 对于大对象这可以节省大量序列化开销 堆外内存读写:即是否支持直接读写native内存 数值类型可空:是否支持基本类型为null , 比如Java的Integer等装箱类型以及python的int/float可能为null 。