java序列化:protobuf与json的比较(代码片段)

九师兄 九师兄     2023-03-09     751

关键词:

1.概述

转载:序列化:ProtoBuf 与 JSON 的比较!

介绍

ProtoBuf 是google团队开发的用于高效存储和读取结构化数据的工具。什么是结构化数据呢,正如字面上表达的,就是带有一定结构的数据。比如电话簿上有很多记录数据,每条记录包含姓名、ID、邮件、电话等,这种结构重复出现。

XML、JSON 也可以用来存储此类结构化数据,但是使用ProtoBuf表示的数据能更加高效,并且将数据压缩得更小。

原理

ProtoBuf 是通过ProtoBuf编译器将与编程语言无关的特有的.proto后缀的数据结构文件编译成各个编程语言(Java,C/C++,Python)专用的类文件,然后通过Google提供的各个编程语言的支持库lib即可调用API。(关于proto结构体怎么编写,可自行查阅文档)

ProtoBuf编译器安装

Mac: brew install protobuf

ProtoBuf使用案例

先创建一个proto文件

message.proto

syntax = "proto3";

message Person 
    int32 id = 1;
    string name = 2;

    repeated Phone phone = 4;

    enum PhoneType 
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    

    message Phone 
        string number = 1;
        PhoneType type = 2;
    

创建一个Java项目

并且将proto文件放置src/main/proto文件夹下

编译proto文件至Java版本
用命令行 cd 到src/main目录下

终端执行命令: protoc --java_out=./java ./proto/*.proto

会发现,在src/main/java里已经生成里对应的Java类

依赖Java版本的ProtoBuf支持库
这里只举一个用Gradle使用依赖的栗子

implementation 'com.google.protobuf:protobuf-java:3.9.1'

将Java对象转为ProtoBuf数据

Message.Person.Phone.Builder phoneBuilder = Message.Person.Phone.newBuilder();
Message.Person.Phone phone1 = phoneBuilder
        .setNumber("100860")
        .setType(Message.Person.PhoneType.HOME)
        .build();
Message.Person.Phone phone2 = phoneBuilder
        .setNumber("100100")
        .setType(Message.Person.PhoneType.MOBILE)
        .build();
Message.Person.Builder personBuilder = Message.Person.newBuilder();
personBuilder.setId(1994);
personBuilder.setName("XIAOLEI");
personBuilder.addPhone(phone1);
personBuilder.addPhone(phone2);

Message.Person person = personBuilder.build();
long old = System.currentTimeMillis();
byte[] buff = person.toByteArray();
System.out.println("ProtoBuf 编码耗时:" + (System.currentTimeMillis() - old));
System.out.println(Arrays.toString(buff));
System.out.println("ProtoBuf 数据长度:" + buff.length);ProtoBuf数据,转换回Java对象
System.out.println("-开始解码-");
old = System.currentTimeMillis();
Message.Person personOut = Message.Person.parseFrom(buff);
System.out.println("ProtoBuf 解码耗时:" + (System.currentTimeMillis() - old));
System.out.printf("Id:%d, Name:%s\\n", personOut.getId(), personOut.getName());
List<Message.Person.Phone> phoneList = personOut.getPhoneList();
for (Message.Person.Phone phone : phoneList) 
    System.out.printf("手机号:%s (%s)\\n", phone.getNumber(), phone.getType());

比较

为了能体现ProtoBuf的优势,我写了同样结构体的Java类,并且将Java对象转换成JSON数据,来与ProtoBuf进行比较。JSON编译库使用Google提供的GSON库,JSON的部分代码就不贴出来了,直接展示结果

运行 1 次

【 JSON 开始编码 】
JSON 编码1次,耗时:22ms
JSON 数据长度:106
-开始解码-
JSON 解码1次,耗时:1ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码1,耗时:32ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码1,耗时:3ms

运行 10 次

【 JSON 开始编码 】
JSON 编码10次,耗时:22ms
JSON 数据长度:106
-开始解码-
JSON 解码10次,耗时:4ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码10,耗时:29ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码10,耗时:3ms

运行 100 次

【 JSON 开始编码 】
JSON 编码100次,耗时:32ms
JSON 数据长度:106
-开始解码-
JSON 解码100次,耗时:8ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码100,耗时:31ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码100,耗时:4ms

运行 1000 次

【 JSON 开始编码 】
JSON 编码1000次,耗时:39ms
JSON 数据长度:106
-开始解码-
JSON 解码1000次,耗时:21ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码1000,耗时:37ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码1000,耗时:8ms

运行 1万 次

【 JSON 开始编码 】
JSON 编码10000次,耗时:126ms
JSON 数据长度:106
-开始解码-
JSON 解码10000次,耗时:93ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码10000,耗时:49ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码10000,耗时:23ms

运行 10万 次

【 JSON 开始编码 】
JSON 编码100000次,耗时:248ms
JSON 数据长度:106
-开始解码-
JSON 解码100000次,耗时:180ms

【 ProtoBuf 开始编码 】
ProtoBuf 编码100000,耗时:51ms
ProtoBuf 数据长度:34
-开始解码-
ProtoBuf 解码100000,耗时:58ms

总结

编解码性能
上述栗子只是简单的采样,实际上据我的实验发现

次数在1千以下,ProtoBuf的编码与解码性能,都与JSON不相上下,甚至还有比JSON差的趋势
次数在2千以上,ProtoBuf的编码解码性能,都比JSON高出很多
次数在10万以上,ProtoBuf的编解码性能就很明显了,远远高出JSON的性能

内存占用

ProtoBuf的内存34,而JSON到达106,ProtoBuf的内存占用只有JSON的1/3.

结尾

其实这次实验有很多可待优化的地方,就算是这种粗略的测试,也能看出来ProtoBuf的优势。

兼容

新增字段
在proto文件中新增 nickname 字段
生成Java文件
用老proto字节数组数据,转换成对象

Id:1992, Name:XIAOLEI
手机号:100860 (HOME)
手机号:100100 (MOBILE)
getNickname=

结果,是可以转换成功。

删除字段
在proto文件中删除 name 字段
生成Java文件
用老proto字节数组数据,转换成对象

Id:1992, Name:null
手机号:100860 (HOME)
手机号:100100 (MOBILE)
结果,是可以转换成功。

使用 ProtoBuf 序列化动态 JSON - Java

】使用ProtoBuf序列化动态JSON-Java【英文标题】:SerializationofDynamicJSONusingProtoBuf-Java【发布时间】:2021-05-0810:51:56【问题描述】:需要一些见解:如何使用Protobuf序列化编写用于序列化包含JSONObject作为属性的javaPOJO类的proto文件。我... 查看详情

protobuf详解(代码片段)

...构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或RPC数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了C++、Java、Python三... 查看详情

Protobuf C++ 与 Android Java

...一个android项目,在该项目中我们使用Google的Protobuf库进行序列化/反序列化。过去,我曾使用C++开发Protobuf。假设我有一个带有一个protobuf对象的.proto文件:messageLoginAckenumLoginResul 查看详情

Avro 与 Protobuf 的性能指标

...关,但作为kafka消息生产者的代码在jruby中。对消息进行序列化和反序列化也会对系统性能产生影响。有人可以帮助比较Avro和ProtocolBuffer在序列化和 查看详情

C ++ Protobuf到/从JSON转换[关闭]

...论】:protobuf消息它们自己并没有足够的信息;我只是反序列化成一个对象模型(protobuf),然后序列化(你选择的jso 查看详情

protobuf简介

参考技术AProtoBuf是一种无关语言,无关平台的序列化结构数据的方法,可用于通信协议、数据存储等XML:数据较为冗余,需要成对的闭合标签JSON:使用键值对方式,压缩了一定的数据空间并且具有可读性ProtoBuf:适合高性能,对... 查看详情

asp.netcore使用protobuf

在一些性能要求很高的应用中,使用protocolbuffer序列化,优于Json。而且protocolbuffer向后兼容的能力比较好。由于Asp.netcore采用了全新的MiddleWare方式,因此使用protobuf序列化,只需要使用Protobuf-net修饰需要序列化的对象,并在MVC初... 查看详情

protobuf协议的java应用例子

...样,是一个规定好的数据传播格式。不过,它的序列化和反序列化的效率太变态了……来看看几张图你就知道它有多变态。Protobuf的Java实例一、安装Protobuf去Protobuf的GitHub下载,解压。如果你是Windows环境&#x 查看详情

了解一下protobuf

...进行网络通信调用的时候,总是需要将内存的数据块经过序列化,转换成为一种可以通过网络流进行传输的格式。而这种格式在经过了传输之后再经过序列化,能还原成我们预想中的数据结构。那么我们对于这种用于中间网络传... 查看详情

protobuf源码解析与netty+rpc实战(代码片段)

...tobuf2.1protobuf工作流程protobuf全称是protocolbuffers,它是一个序列化/反序列化框架 查看详情

netty4.xunity与netty使用protobuf(代码片段)

...的特点是数据小、编解码性能高、支持多种语言,它序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一。更加详细请阅读下面2篇文章:【GoogleProtobuf】windows下protobuf的环境搭建(一)【G... 查看详情

[tdw]protobuf在腾讯数据仓库tdw的使用

...sdn.net/article/a/2014-06-06/15818975protobuf是google提供的一个开源序列化框架,类似于XML、JSON这样的数据表示语言,其最大的特点是基于二进制,因此比传统的XML表示高效短小得多。虽然是二进制数据格式,但并没有因此变得复杂,开... 查看详情

浅析protobuf应用(代码片段)

...lBuffers(简称protobuf)是谷歌的一项技术,用于结构化的数据序列化、反序列化,常用于RPC系统(RemoteProcedureCallProtocolSystem)和持续数据存储系统。其类似于XML生成和解析,但protobuf的效率高于XML,不过protobuf生成的是字节码,可读... 查看详情

protobuf编译安装

...吧,网上对比的文章很多,我主要关注以下几点1、protobuf序列化性能最好,序列化后字节数最少。2、protobuf是单纯的序列化框架,不自带通信层,因为通信层我要用mina或netty,之前用的比较多,比较熟悉。3、avro序列化的时候,... 查看详情

grpc笔记与相关问题

...术A为什么要用RPC,数据编码,请求映射?数据编码就是序列化,反序列化,将对象变成字节流发送给服务端,服务端将收到的字节流再转化为对象常见的序列化,反序列化工具XML,JSON,Protobuf。既然Protobuf在某些场景下效率要比JSON... 查看详情

googleprotobuf数据类型_理解protobuf数据格式解析(代码片段)

...言和平台,具有简单,数据量小,快速等优点。目前用于序列化与反序列化官方支持的语言有C++,C#,GO,JAVA,PYTHON。适用于大小在1M以内的数据,因为像在移动设备平台,内存是很珍贵。 protobuf格式的特点1.效率高/性能好对... 查看详情

protobuf从入门到“顺手”(代码片段)

...一些实用技巧。全文基于最新protobuf3,并用python举例1.概述序列化(serialization、marshalling)的过程是指将数据结构或者对象的状态转换成可以存储(比如文件、内存)或者传输的格式(比如网络)。反向操作就是反序列化(deserialization、unmar... 查看详情

protobuf介绍和语法(代码片段)

...ProtocolBuffers,是Google公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议。        与XML和JSON格式相比,protobuf更小、更快、更便捷。protobuf是跨语言的,并 查看详情