ProtoBuf 是google團隊開發的用於高效存儲和讀取結構化數據的工具。什麼是結構化數據呢,正如字面上表達的,就是帶有必定結構的數據。好比電話簿上有不少記錄數據,每條記錄包含姓名、ID、郵件、電話等,這種結構重複出現。java
XML、JSON 也能夠用來存儲此類結構化數據,可是使用ProtoBuf表示的數據能更加高效,而且將數據壓縮得更小。編程
ProtoBuf 是經過ProtoBuf編譯器將與編程語言無關的特有的 .proto 後綴的數據結構文件編譯成各個編程語言(Java,C/C++,Python)專用的類文件,而後經過Google提供的各個編程語言的支持庫lib便可調用API。(關於proto結構體怎麼編寫,可自行查閱文檔)數組
Mac :
brew install protobuf
數據結構
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; } }
而且將proto文件放置 src/main/proto 文件夾下工具
這裏只舉一個用Gradle使用依賴的栗子性能
implementation 'com.google.protobuf:protobuf-java:3.9.1'
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);
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的部分代碼就不貼出來了,直接展現結果測試
【 JSON 開始編碼 】 JSON 編碼1次,耗時:22ms JSON 數據長度:106 -開始解碼- JSON 解碼1次,耗時:1ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼1次,耗時:32ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼1次,耗時:3ms
【 JSON 開始編碼 】 JSON 編碼10次,耗時:22ms JSON 數據長度:106 -開始解碼- JSON 解碼10次,耗時:4ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼10次,耗時:29ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼10次,耗時:3ms
【 JSON 開始編碼 】 JSON 編碼100次,耗時:32ms JSON 數據長度:106 -開始解碼- JSON 解碼100次,耗時:8ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼100次,耗時:31ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼100次,耗時:4ms
【 JSON 開始編碼 】 JSON 編碼1000次,耗時:39ms JSON 數據長度:106 -開始解碼- JSON 解碼1000次,耗時:21ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼1000次,耗時:37ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼1000次,耗時:8ms
【 JSON 開始編碼 】 JSON 編碼10000次,耗時:126ms JSON 數據長度:106 -開始解碼- JSON 解碼10000次,耗時:93ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼10000次,耗時:49ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼10000次,耗時:23ms
【 JSON 開始編碼 】 JSON 編碼100000次,耗時:248ms JSON 數據長度:106 -開始解碼- JSON 解碼100000次,耗時:180ms 【 ProtoBuf 開始編碼 】 ProtoBuf 編碼100000次,耗時:51ms ProtoBuf 數據長度:34 -開始解碼- ProtoBuf 解碼100000次,耗時:58ms
上述栗子只是簡單的採樣,實際上據個人實驗發現優化
ProtoBuf的內存34,而JSON到達106 ,ProtoBuf的內存佔用只有JSON的1/3.ui
其實此次實驗有不少可待優化的地方,就算是這種粗略的測試,也能看出來ProtoBuf的優點。
Id:1994, Name:XIAOLEI 手機號:100860 (HOME) 手機號:100100 (MOBILE) getNickname=
結果,是能夠轉換成功。
Id:1994, Name:null 手機號:100860 (HOME) 手機號:100100 (MOBILE)
結果,是能夠轉換成功。
END