为什么专门开一个坑,来使用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

Protocol buffers--python 实践(二) protocol buffers vs json的更多相关文章

  1. 机器学习算法与Python实践之(二)支持向量机(SVM)初级

    机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 zouxy09@qq.com http://blog.csdn.net/ ...

  2. P4语言编程快速开始 实践二

    参考:P4语言编程快速开始 上一篇系列博客:P4语言编程快速开始 实践二 Demo 2 本Demo所做的修改及实现的功能: 为simple_router添加一个计数器(counter),该计数器附加( ...

  3. WebSocket原理与实践(二)---WebSocket协议

    WebSocket原理与实践(二)---WebSocket协议 WebSocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信问题而设计的.协议定义ws和wss协议,分别为普通请求和基 ...

  4. Python实践:开篇

    一.概述 Python实践 是应用Python解决实际问题的案例集合,这些案例中的Python应用通常 功能各异.大小不一. 该系列文章是本人应用Python的实践总结,会不定期更新. 二.目录 Py ...

  5. Python实践之(七)逻辑回归(Logistic Regression)

    机器学习算法与Python实践之(七)逻辑回归(Logistic Regression) zouxy09@qq.com http://blog.csdn.net/zouxy09 机器学习算法与Pyth ...

  6. 机器学习算法与Python实践之(四)支持向量机(SVM)实现

    机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...

  7. 机器学习算法与Python实践之(三)支持向量机(SVM)进阶

    机器学习算法与Python实践之(三)支持向量机(SVM)进阶 机器学习算法与Python实践之(三)支持向量机(SVM)进阶 zouxy09@qq.com http://blog.csdn.net/ ...

  8. 机器学习算法与Python实践之(五)k均值聚类(k-means)

    机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学 ...

  9. (转) K-Means聚类的Python实践

    本文转自: http://python.jobbole.com/87343/ K-Means聚类的Python实践 2017/02/11 · 实践项目 · K-means, 机器学习 分享到:1 原文 ...

  10. 机器学习算法与Python实践之(六)二分k均值聚类

    http://blog.csdn.net/zouxy09/article/details/17590137 机器学习算法与Python实践之(六)二分k均值聚类 zouxy09@qq.com http ...

随机推荐

  1. socket编程解决粘包和丢包问题

    ##socket 丢包粘包解决方式 采用固定头部长度(一般为4个字节),包头保存的是包体的长度 header+body 包头+包体 下面的例子不是按照上图中规定的格式编写的,但是思路都是一样的,先读出 ...

  2. java发送163邮件

    在服务挂掉后,可以采用发送邮件的方式来通知开发人员进行异常处理 import java.io.IOException; import java.util.Properties; import java ...

  3. UVA1627-Team them up!(动态规划)

    Problem UVA1627-Team them up! Total Submissions:3577  Solved:648 Time Limit: 3000 mSec Problem Descr ...

  4. 理解 tf.Variable、tf.get_variable以及范围命名方法tf.variable_scope、tf.name_scope

    tensorflow提供了通过变量名称来创建或者获取一个变量的机制.通过这个机制,在不同的函数中可以直接通过变量的名字来使用变量,而不需要将变量通过参数的形式到处传递. 1. tf.Variable( ...

  5. 手动设定统计数据 set_table_stats

    PROCEDURE SET_TABLE_STATS Argument Name Type In/Out Default? ------------------------------ -------- ...

  6. gcc 找不到 boot python 链接库的问题: /usr/bin/ld: cannot find -lboost_python

    问题: Ubuntu 14.04,gcc 4.8.4,以默认方式编译 boost 1.67 后,使用 Boost.Python 时,gcc 提示找不到 boost python 链接库. 方案: 查看 ...

  7. PEP8 python规范神器

    如需转载,请注明出处:小婷儿的博客:https://www.cnblogs.com/xxtalhr/p/10645992.html 一.Jupyter notebook 篇 Jupyter noteb ...

  8. eclipse svn合并小结

    合并时候,当前在哪个分支上,哪个分支即为“主干” 弱化主干 分支的概念.svn原则上并没有主干 分子 主 从的概念.从一个项目衍生(分支)出来的版本,都可以是主,也可以是从. 版本之间互相合并原理 文 ...

  9. 第一行代码:以太坊(2)-使用Solidity语言开发和测试智能合约

    智能合约是以太坊的核心之一,用户可以利用智能合约实现更灵活的代币以及其他DApp.不过在深入讲解如何开发智能合约之前,需要先介绍一下以太坊中用于开发智能合约的Solidity语言,以及相关的开发和测试 ...

  10. Windows Community Toolkit 4.0 - DataGrid - Part03

    概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Part02 中,我们针对 DataGrid 控件的 Utilities 部分做了详细分享.而在 ...