zoukankan      html  css  js  c++  java
  • Protocol buffers--python 实践(二) protocol buffers vs json

    为什么专门开一个坑,来使用pb。放弃本在各平台上都支持得很好的json而使用pb的一个归根到底的理由,就是希望在保证强类型和跨平台的情况下,能够更轻,更快,更简单。既然是奔着这个目标去的,到底多快我需要一个合理的解释。

    在使用pure python官方库的的情况下,对比了pb和json标准库,还有simplejson库的速度。

    使用的.proto文件文件如下:

    syntax = "proto2";
    
    package hello_word;
    
    message SayHi {
        required int32 id = 1;
        required string something = 2;
        optional string extra_info = 3;
    }

    python文件可以根据这个生成对应的SayHi obejct。

    测试各库序列化速度的代码如下所示:

    # coding: utf-8
    import timeit
    
    
    # 序列化
    x = """
    say_hi.SerializeToString()
    """
    
    y = """
    json.dumps(ppa)
    """
    
    z = """
    simplejson.dumps(pl)
    """
    
    print min(timeit.repeat(stmt=x, setup="import say_hi_pb2;"
                                      "say_hi = say_hi_pb2.SayHi();"
                                      "say_hi.id = 13423;"
                                      "say_hi.something = 'axiba';"
                                      "say_hi.extra_info = 'xiba';", repeat=5, number=100000))
    
    print min(timeit.repeat(stmt=y, setup="import json; "
                                      "ppa={"
                                      "'id': 13423,"
                                      "'something': 'axiba',"
                                      "'extra_info': 'xiba',"
                                      "};", repeat=5, number=100000))
    
    print min(timeit.repeat(stmt=z, setup="import simplejson; "
                                      "pl={"
                                      "'id': 13423,"
                                      "'something': 'axiba',"
                                      "'extra_info': 'xiba',"
                                      "};", repeat=5, number=100000))

    输出:

    1.08438277245
    0.398800134659
    0.707333087921

    测试各库反序列化速度的代码如下所示:

    # coding: utf-8
    import timeit
    
    # 反序列化
    x = """
    say_hi.ParseFromString(p)
    """
    y = """
    json.loads(p1)
    """
    z = """
    simplejson.loads(p2)
    """
    
    
    print min(timeit.repeat(stmt=x, setup="import say_hi_pb2;"
                                      "say_hi = say_hi_pb2.SayHi();"
                                      "say_hi.id = 13423;"
                                      "say_hi.something = 'axiba';"
                                      "say_hi.extra_info = 'xiba';"
                                      "p = say_hi.SerializeToString()", repeat=5, number=100000))
    
    print min(timeit.repeat(stmt=y, setup="import json; "
                                      "ppa={"
                                      "'id': 13423,"
                                      "'something': 'axiba',"
                                      "'extra_info': 'xiba',"
                                      "};"
                                      "p1 = json.dumps(ppa)", repeat=5, number=100000))
    
    print min(timeit.repeat(stmt=z, setup="import simplejson; "
                                      "pl={"
                                      "'id': 13423,"
                                      "'something': 'axiba',"
                                      "'extra_info': 'xiba',"
                                      "};"
                                      "p2 = simplejson.dumps(pl)", repeat=5, number=100000))
    输出:

    0.924090862274
    0.492631912231
    0.283575057983

    从上面的数据可以看出,在我使用的版本3.1.0.post1的情况下,纯python实现pb序列化的速度略慢于json原生库两倍多,比simplejson库慢百分之30。在反序列化的速度测试中,依然是pb速度最慢两倍慢于原生json库,慢于simplejson库3倍多。这样看起来差距似乎被优化得不那么大了。记得以前在使用pb2.x库的时候,python序列化常慢于simplejson 3倍以上是非常正常的事情。各分析性能的文章都可以看到 too slow这个描述。由于二进制存储,以及pb独特的编码二进制的方式,从大小的角度来说,pb远远小于json,但是速度连json都快不过,我们有什么理由放弃使用方便可依赖的json转而使用pb呢?这的确没有什么说服力。

    然而,pb官方提供了一个c++实现 runtime for python,按照实践一中的方法,安装好最新的pb库,并且按照文档编译好,然后安装python 的c++实现,就可以让pb使用c++实现进行序列化反序列。其他生成代码之类的所有不用变,调用代码也不用变,只需要安装好就可以了。安装好之后可以看到

    Using /Users/piperck/Desktop/grpc/lib/python2.7/site-packages
    Finished processing dependencies for protobuf==3.1.0

    再次使用pip list查看我们的pb的时候可以发现,已经被该库替代。

    让我们来重新运行一下 序列化和反序列化的代码:

    序列化输出:
    0.085785150528
    0.403172016144
    0.755691051483
    
    反序列化输出:
    0.090231180191
    0.499733924866
    0.297739028931

    可以看到几乎比pure python的实现快近10倍。如果把序列化和反序列按照一次计算进行计算的话,也比我们通常使用的simplejson库快上4到5倍。再频繁调用序列化反序列化的应用中,可以说还是比较大的性能提升了,可以使得你的代码更轻更快,而且强类型映射可以检查错误。

    别以为到这里就完了。还有一个更快速的库,但是现在只支持proto2,叫Pyrobuf Library。基于cPython实现,根据作者的说法,他要比c++ backend for python 还要快上2-4倍。让我们来尝试一下。

    首先安装一下: 

    pip install pyrobuf

    如果不行可以尝试使用:

    pip install pyrobuf -v -v -v --upgrade --force --no-cache

    安装好之后,按照官网的提示,使用pyrobuf 的 cli命令行界面,对.proto文件进行编译,得到.pxd和.pyx文件,还有.o和.c还有.so的文件(注意他们需要在同一个文件夹下)。

     一切完成之后书写代码 测试速度:

    import timeit
    
    
    o = """
    p.SerializeToString()
    """
    
    print min(timeit.repeat(stmt=o, setup=
                            "from hello_world_say_hi_proto import SayHi;"
                            "p = SayHi();"
                            "p.id = 3;"
                            "p.something = 'axiba';"
                            "p.extra_info = 'xiba'", repeat=5, number=100000))
    
    o = """
    p.ParseFromString(oi)
    """
    
    print min(timeit.repeat(stmt=o, setup=
                            "from hello_world_say_hi_proto import SayHi;"
                            "p = SayHi();"
                            "p.id = 3;"
                            "p.something = 'axiba';"
                            "p.extra_info = 'xiba';"
                            "oi = p.SerializeToString()", repeat=5, number=100000))

    输出:

    0.069412946701
    0.0525119304657

    对比上面使用c++ backend的pb来看,反序列化勉强快到2倍,而序列化几乎没有什么特别大的优势。可能得益于使用最新版pb3.10的关系,在google的不断优化下,已经没有那么大差距了吧。因为使用cPython比较麻烦,还会多出不少编译文件。所以没什么提升的情况下,按照个人的需求使用吧。

    Reference:

    https://github.com/google/protobuf/tree/master/python  pb-github库

    https://github.com/appnexus/pyrobuf  Pyrobuf Library

    http://techblog.appnexus.com/blog/2015/12/22/pyrobuf-a-faster-python-protobuf-library-written-in-cython/  pyrobuf-a-faster-python-protobuf-library-written-in-cython

  • 相关阅读:
    摄影初识之一
    Photoshop CS6的安装
    chcon可实现对文件的SEAndroid安全标签的修改
    ubuntu启动失败the system is running in low graphics mode
    将ubuntu14.04设置为文本模式启动?
    Android数据库之SQLite数据库
    系统崩溃分析
    Oops 的栈信息分析
    android framework 之JNI
    SecureCRT语法高亮设置
  • 原文地址:https://www.cnblogs.com/piperck/p/6291526.html
Copyright © 2011-2022 走看看