导航菜单

经典英文歌曲-比json快5倍的protobuf了解一下

之前在网络通讯和通用数据交换等运用场景中常常运用的技能是 JSON 或 XML,而在最近的开发中触摸到了 Google 的 ProtoBuf。在查阅相关材料学习 ProtoBuf 以及研读其源码之后,发现其在功率、兼容性等方面十分超卓。在今后的项目技能选型中,尤其是网络通讯、通用数据交换等场景应该会优先挑选 ProtoBuf。

自己在学习 ProtoBuf 的过程中翻译了官方的首要文档,一来当然是在学习 ProtoBuf,二来是培育阅览英文文档的才能,三来是由于 Google 的文档?不存在的!看完这些文档对 ProtoBuf 应该就有相当程度的了解了。

可是官方文档更多的是作为查阅和威望参看,并不意味着看完官方文档就能立马了解其原理,本文以及接下来的几篇文章会对 ProtoBuf 的编码、序列化、反序列化、反射等原理做一些详细介绍,一同也会尽量将这些原理表达的更为通俗易懂。

何为 ProtoBuf

咱们先来看看官方文档给出的界说和描绘:

protocol buffers 是一种言语无关、渠道无关、可扩展的序列化结构数据的办法,它可用于(数据)通讯协议、数据存储等。Protoc经典英文歌曲-比json快5倍的protobuf了解一下ol Buffers 是一种灵敏,高效,自动化机制的结构数据序列化办法-可类比 XML,可是比 XML 更小(3 ~ 10倍)经典英文歌曲-比json快5倍的protobuf了解一下、更快(20 ~ 100倍)、更为简略。你能够界说数据的结构,然后运用特别生成的源代码轻松的在各种数据流中运用各种言语进行编写和读取结构数据。你乃至能够更新数据结构,而不损坏由旧数据结构编译的已布置程序。

简略来讲, ProtoBuf 是结构数据序列化办法,可简略类比于 XML,其具有以下特色:

  • 言语无关、渠道无关。即 ProtoBuf 支撑 Java、C++、Python 等多种言语,支撑多个渠道
  • 高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简略
  • 扩展性、兼容性好。你能够更新数据结构,而不影响和损坏原有的旧程序
序列化:将结构数据方针转换成能够被存储和传输(例如网络传输)的格局,一同应当要确保这个序列化结果在之后(可能在另一个核算环境中)能够被重建回本来的结构数据或方针。 更为翔实的介绍可参看 维基百科。 类比于 XML:这儿首要指在数据通讯和数据存储运用场景中序列化方面的类比,但个人认为 XML 作为一种扩展符号言语和 ProtoBuf 仍是有着本质差异的。

运用 ProtoBuf

对 ProtoBuf 的基本概念有了必定了解之后,咱们来看看详细该怎么运用 ProtoBuf。

第一步,创立 .proto 文件,界说数据结构,如下例1所示:

// 例1: 在 xxx.proto 文件中界说 Example1 message
message Example1 {
optional string stringVal = 1;
optional bytes bytesVal = 2;
message EmbeddedMessage {
int32 int32Val = 1;
string stringVal = 2;
}
optional EmbeddedMessage embeddedExample1 = 3;
repeated int32 repeatedInt32Val = 4;
repeated string repeatedStringVal = 5;
}

咱们在上例中界说了一个名为 Example1 的 音讯,语法很简略,message 要害字后跟上音讯称号:

message xxx {
}

之后咱们在其间界说了 message 具有的字段,方式为:

message xxx {
// 字段规矩:required -> 字段只能也有必要呈现 1 次
// 字段规矩:optional -> 字段可呈现 0 次或1次
// 字段规矩:repeated -> 字段可呈现恣意屡次(包含 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除掉 19000 到 19999 之间的数字)
字段规矩 类型 称号 = 字段编号;
}

在上例中,咱们界说了:

  • 类型 string,名为 stringVal 的 optional 可选字段,字段编号为 1,此字段可呈现 0 或 1 次
  • 类型 bytes,名为 bytesVal 的 optional 可选字段,字段编号为 2,此字段可呈现 0 或 1 次
  • 类型 EmbeddedMessage(自界说的内嵌 message 类型),名为 embeddedExample1 的 optional 可选字段,字段编号为 3,此字段可呈现 0 或 1 次
  • 类型 int32,名为 repeatedInt32Val 的 repeated 可重复字段,字段编号为 4,此字段可呈现 恣意屡次(包含 0)
  • 类型 string,名为 repeatedStringVal 的 repeated 可重复字段,字段编号为 5,此字段可呈现 恣意屡次(包含 0)

第二霍震霆老婆步,protoc 编译 .proto 文件生成读写接口

咱们在 .proto 文件中界说了数据结构,这些数据结构是面向开发者和事务程序的,并不面向存储和传输。

当需求把这些数据进行存储或传输时,就需求将这些结构数据进行序列化、反序列化以及读写。那么怎么完成呢?不必忧虑, ProtoBuf 将会为咱们供给相应的接口代码。怎么供给?答案便是经过 protoc 这个编译器。

可经过如下指令生成相应的接口代码:

// $SRC_DIR: .proto 地点的源目录
// --cpp_out: 生成 c++ 代码
// $DST_DIR: 生成代码的方针目录
// xxx.proto: 要针对哪个 proto 文件生成接口代码
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto

终究生成的代码将供给相似如下的接口:

第三步,调用接口完成序列化、反序列化以及读写

针对第一步中例1界说的 message,咱们能够调用第二步中生成的接口,完成测验代码如下:

//
// Created by yue on 18-7-21.
//
#include
#include
#include
#include "single_length_delimited_all.pb.h"
int main() {
Example1 example1;
example1.set_stringval("hello,world");
example1.set_bytesval("are you ok?");
Example1_EmbeddedMessage *embeddedExample2 = new Example1_EmbeddedMessage();
embeddedExample2->set_int32val(1);
embeddedExample2->set_stringval("embeddedInfo");
example1.set_allocated_embeddedexample1(embeddedExample2);
example1.add_repeatedint32val(2);
example1.add_repeatedint32val(3);
example1.add_repeatedstringval("repeated1");
example1.add_repeatedstringval("repeated2");
std::string filename = "single_length_delimited_all_example1_val_result";
std::fstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary);
if (!example1.SerializeToOstream(&output)) {
std::cerr << "Failed to write example1." << std::endl;
exit(-1);
}
return 0;
}

关于 ProtoBuf 的一些考虑

官方文档以及网上许多文章说到 ProtoBuf 可类比 XML 或 JSON。

那么 ProtoBuf 是否就等同于 XML 和 JSON 呢,它们是否具有完经典英文歌曲-比json快5倍的protobuf了解一下全相同的运用场景呢?

个人认为假如要将 ProtoBuf、XML、JSON 三者放到一同去比较,应该差异两个维度。一个是数据结构化,一个是数据序列化。这儿的数据结构化首要面向开发或事务层面,数据序列化面向通讯或存储层面,当然数据序列化也需求“结构”和“格局”,所以这两者之间的差异首要在于面向范畴和场景不同,一般要求和偏要点也会有所不同。数据结构化偏重人类可读性乃至有时会着重语义表达才能,而数据序列化偏重功率和紧缩。

从这两个维度,咱们能够做出下面的一些考虑。

XML 作为一种扩展符号言语,JSON 作为源于 JS 的数据格局,都具有数据结构化的才能。例如 XML 能够衍生出 HTML (尽管 HTML 早于 XML,但从概念上讲,HTML 仅仅预界说标签的 XML),HTML 的效果是符号和表达万维网中资源的结构,以便浏览器更好的展现万维网资源,一同也要尽可能确保其人类可读以便开发人员进行修改,这便是面向事务或开发层面的数据结构化

再如 XML 还可衍生出 RDF/RDFS,进一步表达语义网中资源的联系和语义,相同它着重数据结构化的才能和人类可读。

关于 RDF/RDFS 和语义网的概念可查询相关材料了解,或参看 2-Answer 系列-本体构建模块(一) 和 3-Answer 系列-本体构建模块(二) ,文中有一些简略介绍。

JSON 也是同理,在许多场合更多的是表现了数据结构化的才能,例如作为交互接口的数据结构的表达。在 MongoDB 中选用 JSON 作为查询句子,也是在发挥其数据结构化的才能。

当然,JSON、XML 相同也能够直接被用来数据序列化,实践上许多时分它们也是这么被运用的,例如直接选用 JSON、XML 进行网络通讯传输,此刻 JSON、XML 就成了一种序列化格局,它发挥了数据序列化的才能。可是常常这么被运用,不代表这么做便是合理。实践将 JSON、XML 直接效果数据序列化一般并不是最优挑选,由于它们在速度、功率、空间上并不是最优。换句话说它们更适合数据结构化而非数据序列化。

扯完 XML 和 JSON,咱们来看看 ProtoBuf,相同的 ProtoBuf 也具有数据结构化的才能,其实也便是上面介绍的 message 界说。咱们能够在 .proto 文件中,经过 message、import、内嵌 message 等语法来完成数据结构化,可是很简单能够看出,ProtoBuf 在数据结构化方面和 XML、JSON 相差较大,人类可读性较差,不适合上面说到的 XML、JSON 的一些运用场景。

可是假如从数据序列化的视点你会发现 ProtoBuf 有着显着的优势,功率、速度、空间简直全面占优,看完后边的 ProtoBuf 编码的文章,你更会了解 ProtoBuf 是怎么极尽所能的压榨每一寸空间和功能,而其间的编码原理正是 ProtoBuf 的要害地点,message 的表达才能并不是 ProtoBuf 最要害的要点。所以能够看出 ProtoBuf 要点偏重于数据序列化 而非 数据结构化

终究对这些个人考虑做一些小小的总结:

  1. XML、JSON、ProtoBuf 都具有数据结构化和数据序列化的才能
  2. XML、JSON 更重视数据结构化,重视人类可读性和语义表达才能。ProtoBuf 更重视数据序列化,重视功率、空间、速度,人类可读性差,语义表达才能缺乏(为确保极致的功率,会放弃一部分元信息)
  3. ProtoBuf 的运用场景更为清晰,XML、JSON 的运用场景更为丰厚。
二维码