1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        序列化:ProtoBuf與JSON的比較

        共 5579字,需瀏覽 12分鐘

         ·

        2021-06-27 18:34

        來源:https://my.oschina.net/xiaolei123/blog/3085607

        介紹

        ProtoBuf 是google團隊開發(fā)的用于高效存儲和讀取結(jié)構(gòu)化數(shù)據(jù)的工具。什么是結(jié)構(gòu)化數(shù)據(jù)呢,正如字面上表達的,就是帶有一定結(jié)構(gòu)的數(shù)據(jù)。比如電話簿上有很多記錄數(shù)據(jù),每條記錄包含姓名、ID、郵件、電話等,這種結(jié)構(gòu)重復(fù)出現(xiàn)。

        同類

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

        原理

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

        ProtoBuf編譯器安裝

        Mac : brew install protobuf

        舉個例子

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

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

        3. 編譯proto文件至Java版本

        用命令行 cd 到 src/main 目錄下

        終端執(zhí)行命令 : protoc --java_out=./java ./proto/*.proto

        會發(fā)現(xiàn),在你的src/main/java 里已經(jīng)生成里對應(yīng)的Java類

        4. 依賴Java版本的ProtoBuf支持庫

        這里只舉一個用Gradle使用依賴的栗子

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

        5. 將Java對象轉(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 編碼耗時:" + (System.currentTimeMillis() - old));
        System.out.println(Arrays.toString(buff));
        System.out.println("ProtoBuf 數(shù)據(jù)長度:" + buff.length);

        6. 將ProtoBuf數(shù)據(jù),轉(zhuǎn)換回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", 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());
        }

        比較

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

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

        運行 1 次

        【 JSON 開始編碼 】
        JSON 編碼1次,耗時:22ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼1次,耗時:1ms

        【 ProtoBuf 開始編碼 】
        ProtoBuf 編碼1次,耗時:32ms
        ProtoBuf 數(shù)據(jù)長度:34
        -開始解碼-
        ProtoBuf 解碼1次,耗時:3ms

        運行 10 次

        【 JSON 開始編碼 】
        JSON 編碼10次,耗時:22ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼10次,耗時:4ms

        【 ProtoBuf 開始編碼 】
        ProtoBuf 編碼10次,耗時:29ms
        ProtoBuf 數(shù)據(jù)長度:34
        -開始解碼-
        ProtoBuf 解碼10次,耗時:3ms

        運行 100 次

        【 JSON 開始編碼 】
        JSON 編碼100次,耗時:32ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼100次,耗時:8ms

        【 ProtoBuf 開始編碼 】
        ProtoBuf 編碼100次,耗時:31ms
        ProtoBuf 數(shù)據(jù)長度:34
        -開始解碼-
        ProtoBuf 解碼100次,耗時:4ms

        運行 1000 次

        【 JSON 開始編碼 】
        JSON 編碼1000次,耗時:39ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼1000次,耗時:21ms

        【 ProtoBuf 開始編碼 】
        ProtoBuf 編碼1000次,耗時:37ms
        ProtoBuf 數(shù)據(jù)長度:34
        -開始解碼-
        ProtoBuf 解碼1000次,耗時:8ms

        運行 1萬 次

        【 JSON 開始編碼 】
        JSON 編碼10000次,耗時:126ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼10000次,耗時:93ms

        【 ProtoBuf 開始編碼 】
        ProtoBuf 編碼10000次,耗時:49ms
        ProtoBuf 數(shù)據(jù)長度:34
        -開始解碼-
        ProtoBuf 解碼10000次,耗時:23ms

        運行 10萬 次

        【 JSON 開始編碼 】
        JSON 編碼100000次,耗時:248ms
        JSON 數(shù)據(jù)長度:106
        -開始解碼-
        JSON 解碼100000次,耗時:180ms

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

        總結(jié)

        編解碼性能

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

        • 次數(shù)在1千以下,ProtoBuf 的編碼與解碼性能,都與JSON不相上下,甚至還有比JSON差的趨勢。

        • 次數(shù)在2千以上,ProtoBuf的編碼解碼性能,都比JSON高出很多。

        • 次數(shù)在10萬以上,ProtoBuf的編解碼性能就很明顯了,遠遠高出JSON的性能。

        內(nèi)存占用

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

        結(jié)尾

        其實這次實驗有很多可待優(yōu)化的地方,就算是這種粗略的測試,也能看出來ProtoBuf的優(yōu)勢。

        兼容

        新增字段

        • 在proto文件中新增 nickname 字段

        • 生成Java文件

        • 用老proto字節(jié)數(shù)組數(shù)據(jù),轉(zhuǎn)換成對象

        Id:1994, Name:XIAOLEI
        手機號:100860 (HOME)
        手機號:100100 (MOBILE)
        getNickname=

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

        刪除字段

        • 在proto文件中刪除 name 字段

        • 生成Java文件

        • 用老proto字節(jié)數(shù)組數(shù)據(jù),轉(zhuǎn)換成對象

        Id:1994, Name:null
        手機號:100860 (HOME)
        手機號:100100 (MOBILE)

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

        END


        歡迎添加程序汪個人微信 itwang007  進粉絲群或圍觀朋友圈



        往期資源  需要請自取

        Java項目分享 最新整理全集,找項目不累啦 03版

        臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

        字節(jié)跳動總結(jié)的設(shè)計模式 PDF 火了,完整版開放下載!


        堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實戰(zhàn)進階


        臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

        喜歡就"在看"唄^_^


        瀏覽 31
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            操小骚逼操小骚逼操小骚逼 | 91久久人澡人妻人人澡人人爽 | 欧美乱妇在线 | 成人免费无遮挡无码黄漫视频契约 | 国产高清在线精品一区二区三区 | 无码视频在线播放 | 免费播放片色情A片 | 五月天综合 | 无码人妻视频 | 亚欧精品久久无码产区 |