PHP序列化对比(Protobuf&Json)

概念

  • Json: https://en.wikipedia.org/wiki/JSON
  • Protobuf: https://en.wikipedia.org/wiki/Protocol_Buffers

测试脚本

  • protobuf schema (test.proto)
message Test {
    optional int32 aaa = 1;
    repeated string bbb = 2;
}
  • 编译test.proto
 array(
            'name' => 'aaa',
            'required' => false,
            'type' => 5,
        ),
        self::BBB => array(
            'name' => 'bbb',
            'repeated' => true,
            'type' => 7,
        ),
    );

    /**
     * Constructs new message container and clears its internal state
     *
     * @return null
     */
    public function __construct()
    {
        $this->reset();
    }

    /**
     * Clears message values and sets default ones
     *
     * @return null
     */
    public function reset()
    {
        $this->values[self::AAA] = null;
        $this->values[self::BBB] = array();
    }

    /**
     * Returns field descriptors
     *
     * @return array
     */
    public function fields()
    {
        return self::$fields;
    }

    /**
     * Sets value of 'aaa' property
     *
     * @param int $value Property value
     *
     * @return null
     */
    public function setAaa($value)
    {
        return $this->set(self::AAA, $value);
    }

    /**
     * Returns value of 'aaa' property
     *
     * @return int
     */
    public function getAaa()
    {
        return $this->get(self::AAA);
    }

    /**
     * Appends value to 'bbb' list
     *
     * @param string $value Value to append
     *
     * @return null
     */
    public function appendBbb($value)
    {
        return $this->append(self::BBB, $value);
    }

    /**
     * Clears 'bbb' list
     *
     * @return null
     */
    public function clearBbb()
    {
        return $this->clear(self::BBB);
    }

    /**
     * Returns 'bbb' list
     *
     * @return string[]
     */
    public function getBbb()
    {
        return $this->get(self::BBB);
    }

    /**
     * Returns 'bbb' iterator
     *
     * @return ArrayIterator
     */
    public function getBbbIterator()
    {
        return new ArrayIterator($this->get(self::BBB));
    }

    /**
     * Returns element from 'bbb' list at given offset
     *
     * @param int $offset Position in list
     *
     * @return string
     */
    public function getBbbAt($offset)
    {
        return $this->get(self::BBB, $offset);
    }

    /**
     * Returns count of 'bbb' list
     *
     * @return int
     */
    public function getBbbCount()
    {
        return $this->count(self::BBB);
    }
}
  • php测试脚本
_do_run($test);
        }
        print_r($this->report);
    }

    /**
     * 运行测试数据
     * @param $count
     */
    private function _do_run($count){

        $this->_get_data($count);
        $encode_report  = $this->_encode();
        $decode_report  = $this->_decode();
        $this->report[] = array_merge($encode_report, $decode_report);
    }

    /**
     * 序列化
     * @return array
     */
    private function _encode(){

        //json
        $this->data_json  = null;
        $s_mem            = memory_get_usage();
        $s_time           = microtime(true);
        $this->data_json  = json_encode($this->test_data);
        $e_time           = microtime(true);
        $e_mem            = memory_get_usage();
        $length_json      = number_format(mb_strlen($this->data_json) / 1024, 7, '.', '');
        $encode_meme_json = $e_mem - $s_mem;
        $encode_time_json = $e_time - $s_time;

        //protobuf
        $test_obj      = new Test();
        $this->data_pb = null;
        $test_obj->setAaa($this->test_data['aaa']);
        if(isset($this->test_data['bbb']) && count($this->test_data['bbb']) > 0){
            foreach($this->test_data['bbb'] as $b){
                $test_obj->appendBbb($b);
            }
        }
        $s_mem          = memory_get_usage();
        $s_time         = microtime(true);
        $this->data_pb  = $test_obj->serializeToString();
        $e_time         = microtime(true);
        $e_mem          = memory_get_usage();
        $length_pb      = number_format(mb_strlen($this->data_pb) / 1024, 7, '.', '');
        $encode_meme_pb = $e_mem - $s_mem;
        $encode_time_pb = $e_time - $s_time;
        $test_obj       = null;

        return array(
            'length_js'      => $length_json,
            'length_pb'      => $length_pb,
            'length_p'       => ($length_json - $length_pb) * 100 / $length_pb,
            'encode_mem_js'  => $encode_meme_json,
            'encode_mem_pb'  => $encode_meme_pb,
            'encode_mem_p'   => ($encode_meme_json - $encode_meme_pb) * 100 / $encode_meme_pb,
            'encode_time_js' => $encode_time_json,
            'encode_time_pb' => $encode_time_pb,
            'encode_time_p'  => ($encode_time_json - $encode_time_pb) * 100 / $encode_time_pb,
        );
    }

    /**
     * 解序列化
     * @return array
     */
    private function _decode(){

        //json
        $s_mem            = memory_get_usage();
        $s_time           = microtime(true);
        $d                = json_decode($this->data_json, 1);
        $e_time           = microtime(true);
        $e_mem            = memory_get_usage();
        $decode_meme_json = $e_mem - $s_mem;
        $decode_time_json = $e_time - $s_time;
        $d                = null;

        //protobuf
        $test_obj = new Test();
        $s_mem    = memory_get_usage();
        $s_time   = microtime(true);
        $test_obj->parseFromString($this->data_pb);
        $e_time         = microtime(true);
        $e_mem          = memory_get_usage();
        $decode_meme_pb = $e_mem - $s_mem;
        $decode_time_pb = $e_time - $s_time;
        $test_obj       = null;

        return array(
            'decode_mem_js'  => $decode_meme_json,
            'decode_mem_pb'  => $decode_meme_pb,
            'decode_mem_p'   => ($decode_meme_json - $decode_meme_pb) * 100 / $decode_meme_pb,
            'decode_time_js' => $decode_time_json,
            'decode_time_pb' => $decode_time_pb,
            'decode_time_p'  => ($decode_time_json - $decode_time_pb) * 100 / $decode_time_pb,
        );
    }

    /**
     * 构造数据
     * @param $count
     */
    private function _get_data($count){

        $this->test_data['aaa'] = mt_rand(0, $count);
        for($i = 0; $i < $count; $i++){
            $this->test_data['bbb'][] = $this->get_str(100);
        }
    }

    /**
     * 获得随机字符串
     * @param $length
     * @return string
     */
    private function get_str($length){

        $data  = '';
        $count = count(self::$str);
        for($i = 0; $i < $length; $i++){
            $data .= self::$str[mt_rand(0, $count - 1)];
        }

        return $data;
    }
}

$s = new SerializeTest();
$s->run();

  • 执行测试脚本
    php index.php

  • 输出结果

Array
(
    [0] => Array
        (
            [length_js] => 176.8730469
            [length_pb] => 130.8339844
            [length_p] => 35.188917245877
            [encode_mem_js] => 181280
            [encode_mem_pb] => 134024
            [encode_mem_p] => 35.259356533158
            [encode_time_js] => 0.0026960372924805
            [encode_time_pb] => 0.00014805793762207
            [encode_time_p] => 1720.9339774557
            [decode_mem_js] => 297256
            [decode_mem_pb] => 296552
            [decode_mem_p] => 0.23739512800453
            [decode_time_js] => 0.0033869743347168
            [decode_time_pb] => 0.00016999244689941
            [decode_time_p] => 1892.4263674614
        )

    [1] => Array
        (
            [length_js] => 706.4111328
            [length_pb] => 522.8535156
            [length_p] => 35.106891648105
            [encode_mem_js] => 723528
            [encode_mem_pb] => 535440
            [encode_mem_p] => 35.127745405648
            [encode_time_js] => 0.010690927505493
            [encode_time_pb] => 0.00066089630126953
            [encode_time_p] => 1517.6406926407
            [decode_mem_js] => 1186200
            [decode_mem_pb] => 1185464
            [decode_mem_p] => 0.062085394410965
            [decode_time_js] => 0.013932943344116
            [decode_time_pb] => 0.00093817710876465
            [decode_time_p] => 1385.1080050826
        )

    [2] => Array
        (
            [length_js] => 6002.6904297
            [length_pb] => 4443.3632813
            [length_p] => 35.093397718851
            [encode_mem_js] => 6146920
            [encode_mem_pb] => 4550064
            [encode_mem_p] => 35.095242616368
            [encode_time_js] => 0.089380025863647
            [encode_time_pb] => 0.0054750442504883
            [encode_time_p] => 1532.4986936074
            [decode_mem_js] => 10321456
            [decode_mem_pb] => 10320736
            [decode_mem_p] => 0.0069762466552773
            [decode_time_js] => 0.11988496780396
            [decode_time_pb] => 0.0090479850769043
            [decode_time_p] => 1224.9907773386
        )

    [3] => Array
        (
            [length_js] => 23659.4199219
            [length_pb] => 17512.7265625
            [length_p] => 35.098437341915
            [encode_mem_js] => 24227408
            [encode_mem_pb] => 17933072
            [encode_mem_p] => 35.099039361466
            [encode_time_js] => 0.37850999832153
            [encode_time_pb] => 0.025068044662476
            [encode_time_p] => 1409.9302854208
            [decode_mem_js] => 40707576
            [decode_mem_pb] => 40706992
            [decode_mem_p] => 0.0014346429723916
            [decode_time_js] => 0.47448205947876
            [decode_time_pb] => 0.051760911941528
            [decode_time_p] => 816.68025481228
        )

    [4] => Array
        (
            [length_js] => 76635.7978516
            [length_pb] => 56723.3193359
            [length_p] => 35.104572068118
            [encode_mem_js] => 78475224
            [encode_mem_pb] => 58084816
            [encode_mem_p] => 35.104540918232
            [encode_time_js] => 1.1786558628082
            [encode_time_pb] => 0.0988929271698
            [encode_time_p] => 1091.850516048
            [decode_mem_js] => 129246120
            [decode_mem_pb] => 129245304
            [decode_mem_p] => 0.00063135756174166
            [decode_time_js] => 1.509269952774
            [decode_time_pb] => 0.13635492324829
            [decode_time_p] => 1006.8686900478
        )
)
  • 制作报表 https://docs.google.com/spreadsheets/d/1kU0HpUvcG-C6JK8GU-zKSxjKCewYt94lsRqNftaEfME/edit?usp=sharing

  • 报表

    • 数据报表
    • PHP序列化对比(Protobuf&Json)_第1张图片
      数据大小
  • PHP序列化对比(Protobuf&Json)_第2张图片
    内存消耗
  • PHP序列化对比(Protobuf&Json)_第3张图片
    耗时对比
  • 结论

  • protobuf比json在执行时间上是最大的收益,至少一个数量级;

  • 其次是数据包的大小,protobuf比json少三分之二;

  • 序列化的内存消耗protobuf是json的三分之一;

  • protobuf比json略麻烦一些,可以通过自动化脚本优化。

深入了解原理请访问
http://www.jianshu.com/p/ec39f79c0412

你可能感兴趣的:(PHP序列化对比(Protobuf&Json))