ProtoBuf与JSON性能⽐较
序列化:ProtoBuf 与 JSON 的⽐较 !
介绍
ProtoBuf 是google团队开发的⽤于⾼效存储和读取结构化数据的⼯具。什么是结构化数据呢,正如字⾯上表达的,就是带有⼀定结构的数据。⽐如电话簿上有很多记录数据,每条记录包含姓名、ID、邮件、电话等,这种结构重复出现。
同类
XML、JSON 也可以⽤来存储此类结构化数据,但是使⽤ProtoBuf表⽰的数据能更加⾼效,并且将数据压缩得更⼩。
原理
ProtoBuf 是通过ProtoBuf编译器将与编程语⾔⽆关的特有的 .proto 后缀的数据结构⽂件编译成各个编程语⾔(Java,C/C++,Python)专⽤的类⽂件,然后通过Google提供的各个编程语⾔的⽀持库lib即可调⽤API。(关于proto结构体怎么编写,可⾃⾏查阅⽂档)
ProtoBuf编译器安装
Mac : brew install protobuf
举个例⼦python怎么读取json文件
1.先创建⼀个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;
}
}
复制代码
2.创建⼀个Java项⽬
并且将proto⽂件放置 src/main/proto ⽂件夹下
3.编译proto⽂件⾄Java版本
⽤命令⾏ cd 到 src/main ⽬录下
终端执⾏命令 : protoc --java_out=./java ./proto/*.proto
会发现,在你的src/main/java ⾥已经⽣成⾥对应的Java类
4.依赖Java版本的ProtoBuf⽀持库
这⾥只举⼀个⽤Gradle使⽤依赖的栗⼦
implementation 'le.protobuf:protobuf-java:3.9.1'
复制代码
5.将Java对象转为ProtoBuf数据
Message.Person.Phone.Builder phoneBuilder = Message.wBuilder();
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 = wBuilder();
personBuilder.setId(1994);
personBuilder.setName("XIAOLEI");
personBuilder.addPhone(phone1);
personBuilder.addPhone(phone2);
Message.Person person = personBuilder.build();
long old = System.currentTimeMillis();
byte[] buff = ByteArray();
System.out.println("ProtoBuf 编码耗时:" + (System.currentTimeMillis() - old));
System.out.String(buff));
System.out.println("ProtoBuf 数据长度:" + buff.length);
复制代码
6.将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", Id(), Name());
List<Message.Person.Phone> phoneList = PhoneList();
for (Message.Person.Phone phone : phoneList)
{
System.out.printf("⼿机号:%s (%s)\n", Number(), Type());
}
复制代码
⽐较
为了能体现ProtoBuf的优势,我写了同样结构体的Java类,并且将Java对象转换成JSON数据,来与ProtoBuf进⾏⽐较。JSON编译库使⽤Google提供的GSON库,JSON的部分代码就不贴出来了,直接展⽰结果
⽐较结果
运⾏ 1 次
【 JSON 开始编码 】
JSON 编码1次,耗时:22ms
JSON 数据长度:106
-开始解码-
JSON 解码1次,耗时:1ms
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 编码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:1994, Name:XIAOLEI ⼿机号:100860 (HOME) ⼿机号:100100 (MOBILE) getNickname=结果,是可以转换成功。
删除字段
在proto⽂件中删除 name 字段
⽣成Java⽂件
⽤⽼proto字节数组数据,转换成对象
Id:1994, Name:null ⼿机号:100860 (HOME) ⼿机号:100100 (MOBILE)
结果,是可以转换成功。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论