Protobuffer和json 簡單對比(java語言)
阿新 • • 發佈:2019-02-10
一,應用場景
廣告行業多平臺之間, 會用http協議以post的方式傳遞很多上下文資訊. 大平臺(兼有pc和mobile),比如阿里/百度/騰訊目前都以protobuffer作為資料交換格式. 我所知道的純移動流量平臺mongo和小米,採用的json. 不能明白他們做選擇時的考量是什麼, 所以對兩者做了簡單的對比測試(當然,不一定能解決自己的困惑).
二, 案例設計
1, 測試proto協議
2, 最近基本的java bean 類Teacher和Student, 屬性和proto裡的資料完全一致.message Teacher{ required int32 id = 1; required string name = 2; //學生列表 repeated Student students = 3; } message Student { required int32 id = 1; required string name = 2; optional string desc = 3; }
3, 針對以上資料格式, 做三組測試:
a) 混合資料: 如上圖, 屬性中既有數字, 又有字串.
b) 純數字測試: 把上圖中的字元屬性註釋掉. 普通java bean也做對應處理.
c) 純字元測試: 把上圖中的數字屬性註釋掉.
三, 測試編碼
1, proto資料格式的序列化,反序列化以及序列化後文件大小. 程式碼為"混合資料"的程式碼. 三組測試只有屬性不一樣, 做相應的註釋就好.
2. 阿里巴巴的fastjson工具包操作json的測試程式碼. 由於使用靜態方法操作, 所以在junit的setUp()方法中預先載入了JSON類.@Test public void protoSerialization() { User.Teacher.Builder teacher = User.Teacher.newBuilder(); teacher.setId(100); teacher.setName("劉備"); User.Student.Builder student; for(int i=0;i<size;i++){ student = User.Student.newBuilder(); student.setId(101+i); student.setName("趙雲"); student.setDesc("五虎將之一"); teacher.addStudents(student.build()); } List<byte[]> listB = new ArrayList<>(); long start = System.currentTimeMillis(); for(User.Student.Builder s:teacher.getStudentsBuilderList()){ listB.add(s.build().toByteArray()); } System.out.println("protobuffer序列化耗時:"+(System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for(byte[] b:listB){ try { User.Student.parseFrom(b); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } } System.out.println("protobuffer反序列化耗時:"+(System.currentTimeMillis() - start)); try { FileOutputStream fileOutputStream = new FileOutputStream("E:\\temp\\teacher-proto.txt"); fileOutputStream.write(teacher.build().toByteArray()); // teacher.build().writeTo(fileOutputStream); fileOutputStream.close(); } catch (Exception e) { e.printStackTrace(); } }
3. google 的json工具包操作json的測試程式碼@Test public void fastJsonSerialization(){ Teacher teacher = new Teacher(); teacher.setId(100); teacher.setName("劉備"); Student student = null; List<Student> students = new ArrayList<>(); for(int i=0;i<size;i++){ student = new Student(); student.setId(101+i); student.setName("趙雲"); student.setDesc("五虎將之一"); students.add(student); } List<String> jsonStr = new ArrayList<>(); long start = System.currentTimeMillis(); for(Student s:students){ jsonStr.add(JSON.toJSONString(s)); } System.out.println("fastJson序列化耗時:"+(System.currentTimeMillis() - start)); start = System.currentTimeMillis(); for(String str:jsonStr){ JSON.parseObject(str, Student.class); } System.out.println("fastJson反序列化耗時:"+(System.currentTimeMillis() - start)); teacher.setStudents(students); String result = JSON.toJSONString(teacher); try { FileWriter file = new FileWriter("E:\\temp\\teacher-fast-json.txt"); file.write(result); file.close(); } catch (IOException e) { e.printStackTrace(); } }
<span style="white-space:pre"> </span>@Test
public void gJsonSerialization(){
Teacher teacher = new Teacher();
teacher.setId(100);
teacher.setName("劉備");
Student student = null;
List<Student> students = new ArrayList<>();
for(int i=0;i<size;i++){
student = new Student();
student.setId(101+i);
student.setName("趙雲");
student.setDesc("五虎將之一");
students.add(student);
}
List<String> jsonStr = new ArrayList<>();
Gson g = new Gson();
long start = System.currentTimeMillis();
for(Student s:students){
jsonStr.add(g.toJson(s));
}
System.out.println("gson序列化耗時:"+(System.currentTimeMillis() - start));
start = System.currentTimeMillis();
for(String str:jsonStr){
g.fromJson(str, Student.class);
}
System.out.println("gson反序列化耗時:"+(System.currentTimeMillis() - start));
teacher.setStudents(students);
String result = new Gson().toJson(teacher);
try {
FileWriter file = new FileWriter("E:\\temp\\teacher-gson.txt");
file.write(result);
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
三,測試結果
1, 數字字元混合測試
資料格式 | 序列化耗時(ms) | 反序列化耗時(ms) | 檔案大小 |
---|---|---|---|
protobuffer | 61 | 20 | 440k |
fastjson工具處理json | 64 | 60 | 781k |
gson處理json | 112 | 115 | 781k |
2, 純數字測試
資料格式 | 序列化耗時(ms) | 反序列化耗時(ms) | 檔案大小 |
---|---|---|---|
protobuffer | 30 | 24 | 74k |
fastjson工具處理json | 43 | 48 | 180k |
gson處理json | 63 | 106 | 180k |
3, 純字元
資料格式 | 序列化耗時(ms) | 反序列化耗時(ms) | 檔案大小 |
---|---|---|---|
protobuffer | 57 | 19 | 396k |
fastjson工具處理json | 45 | 62 | 630 |
gson處理json | 96 | 95 | 630 |
四, 總結
1. 測試程式碼每次執行雖有細微差異, 但總的來說protobuff先效能和序列化後文件大小方面表現還不錯, 尤其是檔案大小, 比較適合我的應用場景. 跨網傳輸資料就能節約不少成本. 當然, json也有自己的優勢, 不是protobuff能完全取代的, 具體得看應用場景.
2. pb對數字型別的編碼壓縮很大, 在做proto協議涉及時可以適當考慮這一點. 當然會犧牲一些cpu時間.
3. 聽說"pb對巢狀陣列型別會消耗大量記憶體", 未經測試驗證.
4. 以上測試很簡單, 僅供參考.
五, 參考資料