ProtoBuf試用與JSON的比較

介紹

ProtoBuf 是google團(tuán)隊(duì)開(kāi)發(fā)的用于高效存儲(chǔ)和讀取結(jié)構(gòu)化數(shù)據(jù)的工具榨乎。什么是結(jié)構(gòu)化數(shù)據(jù)呢,正如字面上表達(dá)的负饲,就是帶有一定結(jié)構(gòu)的數(shù)據(jù)堤魁。比如電話簿上有很多記錄數(shù)據(jù),每條記錄包含姓名返十、ID妥泉、郵件、電話等洞坑,這種結(jié)構(gòu)重復(fù)出現(xiàn)盲链。

同類

XML、JSON 也可以用來(lái)存儲(chǔ)此類結(jié)構(gòu)化數(shù)據(jù)迟杂,但是使用ProtoBuf表示的數(shù)據(jù)能更加高效刽沾,并且將數(shù)據(jù)壓縮得更小。

原理

ProtoBuf 是通過(guò)ProtoBuf編譯器將與編程語(yǔ)言無(wú)關(guān)的特有的 .proto 后綴的數(shù)據(jù)結(jié)構(gòu)文件編譯成各個(gè)編程語(yǔ)言(Java,C/C++,Python)專用的類文件,然后通過(guò)Google提供的各個(gè)編程語(yǔ)言的支持庫(kù)lib即可調(diào)用API排拷。(關(guān)于proto結(jié)構(gòu)體怎么編寫侧漓,可自行查閱文檔)

ProtoBuf編譯器安裝

Mac : brew install protobuf

舉個(gè)例子

1. 先創(chuàng)建一個(gè)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. 創(chuàng)建一個(gè)Java項(xiàng)目

并且將proto文件放置 src/main/proto 文件夾下

3. 編譯proto文件至Java版本

  • 用命令行 cd 到 src/main 目錄下
  • 終端執(zhí)行命令 : protoc --java_out=./java ./proto/*.proto
  • 會(huì)發(fā)現(xiàn),在你的src/main/java 里已經(jīng)生成里對(duì)應(yīng)的Java類

4. 依賴Java版本的ProtoBuf支持庫(kù)

這里只舉一個(gè)用Gradle使用依賴的栗子

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

5. 將Java對(duì)象轉(zhuǎn)為ProtoBuf數(shù)據(jù)

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 編碼耗時(shí):" + (System.currentTimeMillis() - old));
System.out.println(Arrays.toString(buff));
System.out.println("ProtoBuf 數(shù)據(jù)長(zhǎng)度:" + buff.length);

6. 將ProtoBuf數(shù)據(jù)监氢,轉(zhuǎn)換回Java對(duì)象

System.out.println("-開(kāi)始解碼-");
old = System.currentTimeMillis();
Message.Person personOut = Message.Person.parseFrom(buff);
System.out.println("ProtoBuf 解碼耗時(shí):" + (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("手機(jī)號(hào):%s (%s)\n", phone.getNumber(), phone.getType());
}

比較

為了能體現(xiàn)ProtoBuf的優(yōu)勢(shì)布蔗,我寫了同樣結(jié)構(gòu)體的Java類,并且將Java對(duì)象轉(zhuǎn)換成JSON數(shù)據(jù)忙菠,來(lái)與ProtoBuf進(jìn)行比較何鸡。JSON編譯庫(kù)使用Google提供的GSON庫(kù),JSON的部分代碼就不貼出來(lái)了牛欢,直接展示結(jié)果

比較結(jié)果結(jié)果

  • 運(yùn)行 1 次
【 JSON 開(kāi)始編碼 】
JSON 編碼1次骡男,耗時(shí):22ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼1次,耗時(shí):1ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼1次,耗時(shí):32ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼1次,耗時(shí):3ms
  • 運(yùn)行 10 次
【 JSON 開(kāi)始編碼 】
JSON 編碼10次傍睹,耗時(shí):22ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼10次隔盛,耗時(shí):4ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼10次,耗時(shí):29ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼10次,耗時(shí):3ms
  • 運(yùn)行 100 次
【 JSON 開(kāi)始編碼 】
JSON 編碼100次,耗時(shí):32ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼100次拾稳,耗時(shí):8ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼100次,耗時(shí):31ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼100次,耗時(shí):4ms
  • 運(yùn)行 1000 次
【 JSON 開(kāi)始編碼 】
JSON 編碼1000次吮炕,耗時(shí):39ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼1000次,耗時(shí):21ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼1000次,耗時(shí):37ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼1000次,耗時(shí):8ms
  • 運(yùn)行 1萬(wàn) 次
【 JSON 開(kāi)始編碼 】
JSON 編碼10000次访得,耗時(shí):126ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼10000次龙亲,耗時(shí):93ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼10000次,耗時(shí):49ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼10000次,耗時(shí):23ms
  • 運(yùn)行 10萬(wàn) 次
【 JSON 開(kāi)始編碼 】
JSON 編碼100000次陕凹,耗時(shí):248ms
JSON 數(shù)據(jù)長(zhǎng)度:106
-開(kāi)始解碼-
JSON 解碼100000次,耗時(shí):180ms

【 ProtoBuf 開(kāi)始編碼 】
ProtoBuf 編碼100000次,耗時(shí):51ms
ProtoBuf 數(shù)據(jù)長(zhǎng)度:34
-開(kāi)始解碼-
ProtoBuf 解碼100000次,耗時(shí):58ms

總結(jié)

編解碼性能

上述栗子只是簡(jiǎn)單的采樣鳄炉,實(shí)際上據(jù)我的實(shí)驗(yàn)發(fā)現(xiàn)

  • 次數(shù)在1千以下杜耙,ProtoBuf 的編碼與解碼性能,都與JSON不相上下拂盯,甚至還有比JSON差的趨勢(shì)佑女。
  • 次數(shù)在2千以上,ProtoBuf的編碼解碼性能谈竿,都比JSON高出很多团驱。
  • 次數(shù)在10萬(wàn)以上,ProtoBuf的編解碼性能就很明顯了空凸,遠(yuǎn)遠(yuǎn)高出JSON的性能嚎花。
內(nèi)存占用

ProtoBuf的內(nèi)存34,而JSON到達(dá)106 呀洲,ProtoBuf的內(nèi)存占用只有JSON的1/3.

結(jié)尾

其實(shí)這次實(shí)驗(yàn)有很多可待優(yōu)化的地方贩幻,就算是這種粗略的測(cè)試,也能看出來(lái)ProtoBuf的優(yōu)勢(shì)两嘴。

兼容

新增字段
  • 在proto文件中新增 nickname 字段
  • 生成Java文件
  • 用老proto字節(jié)數(shù)組數(shù)據(jù)丛楚,轉(zhuǎn)換成對(duì)象
Id:1994, Name:XIAOLEI
手機(jī)號(hào):100860 (HOME)
手機(jī)號(hào):100100 (MOBILE)
getNickname=

結(jié)果,是可以轉(zhuǎn)換成功憔辫。

刪除字段
  • 在proto文件中刪除 name 字段
  • 生成Java文件
  • 用老proto字節(jié)數(shù)組數(shù)據(jù)趣些,轉(zhuǎn)換成對(duì)象
Id:1994, Name:null
手機(jī)號(hào):100860 (HOME)
手機(jī)號(hào):100100 (MOBILE)

結(jié)果,是可以轉(zhuǎn)換成功贰您。

老群被封坏平,+新Q群709287944

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锦亦,隨后出現(xiàn)的幾起案子舶替,更是在濱河造成了極大的恐慌,老刑警劉巖杠园,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顾瞪,死亡現(xiàn)場(chǎng)離奇詭異抛蚁,居然都是意外死亡陈醒,警方通過(guò)查閱死者的電腦和手機(jī)瞧甩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肚逸,“玉大人彬坏,你說(shuō)我怎么就攤上這事膝晾。” “怎么了玷犹?”我有些...
    開(kāi)封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵洒疚,是天一觀的道長(zhǎng)歹颓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)油湖,這世上最難降的妖魔是什么巍扛? 我笑而不...
    開(kāi)封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮乏德,結(jié)果婚禮上撤奸,老公的妹妹穿的比我還像新娘。我一直安慰自己喊括,他們只是感情好胧瓜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著郑什,像睡著了一般府喳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蘑拯,一...
    開(kāi)封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天钝满,我揣著相機(jī)與錄音,去河邊找鬼申窘。 笑死弯蚜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剃法。 我是一名探鬼主播碎捺,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贷洲!你這毒婦竟也來(lái)了牵寺?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恩脂,失蹤者是張志新(化名)和其女友劉穎帽氓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體俩块,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黎休,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年浓领,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片势腮。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡联贩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捎拯,到底是詐尸還是另有隱情泪幌,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布署照,位于F島的核電站祸泪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏建芙。R本人自食惡果不足惜没隘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望禁荸。 院中可真熱鬧,春花似錦瑰妄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓜饥。三九已至,卻和暖如春乓土,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狡相。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工尽棕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滔悉。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像曹宴,于是被迫代替她去往敵國(guó)和親歉提。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容