使用Protocol Buffers的C语言拓展提速Python程序的示例


Posted in Python onApril 16, 2015

 Protocol Buffers (类似XML的一种数据描述语言)最新版本2.3里,protoc—py_out命令只生成原生的Python代码。 尽管PB(Protocol Buffers)可以为C++语言生成快速解析和序列化代码,但是这种方式对于Python不适用,并且手动生成的已包装的代码需要非常大的维护工作。在讨论组里,这是一个常见的功能要求,由于一个必备的客户端组件—AppEngine(根据团队介绍名称为AppEngine),生成原生的Python代码有更高的优先级。

幸运的是, PB 2.4版本中本地化代码已被提名,在 svn的分支中已经可以下载,因此你能够使用快速的 PB有一段时间了。 (我们使用 r352版本有一段时间了,还没有遇到任何问题。) PB团队一直不愿轻易指定任何发布日期,在我的威胁下, Kenton Varda提到日期初步定在 2011年初。

我没有在其它地方看见过这个文档,希望它能对其他人有所帮助.

如何做能让它快起来

安装好新的PB库之后并使用 protoc --py_out=...  重新构建好你的PB之后,你需要在运行你的Python程序之前进行环境变量 PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp 的设置,以便于选择C++的,或者PB默认使用的Python实现.

就这样了!这至少就能在可以动态转化/序列化消息的PB运行时库用通用的C++代码了. (注意我们还没有生成任何C++代码.)

它能有多快呢? 我编写了一个简单的程序来获得性能在我们的应用程序中的提升感观:
 

nruns = 1000nwarmups = 100xs = ... # your protobufsdef ser(): return [x.SerializeToString() for x in xs]def parse(ys): for y in ys: pb.Email().ParseFromString(y)
 
t = timeit.Timer(lambda:None)
t.timeit(nwarmups)print 'noop:', t.timeit(nruns) / nruns
 
t = timeit.Timer(ser)
t.timeit(nwarmups)print 'ser:', t.timeit(nruns) / nruns / len(xs)
 
ys = ser()
t = timeit.Timer(lambda: parse(ys))
t.timeit(nwarmups)print 'parse:', t.timeit(nruns) / nruns / len(xs)print 'msg size:', sum(len(y) for y in ys) / len(ys)

以秒为单位,这段程序在我的桌面上给出了如下几个时间结果:
 

$ python sandbox/pbbench.py out.ini
ser: 0.000434461673101
parse: 0.000602062404156
msg size: 10730
 
$ PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp \
> python sandbox/pbbench.py out.ini
ser: 2.86788344383e-05
parse: 7.63910810153e-05
msg size: 10730

这显示出在序列化和转化方面分别有15和8被的速度提升。不坏!但还可以更快.

如何做让它更快

现在我们实际上只是特地针对你的PB生成了一个C++实现,而我们从来没有使用过运行时反射。首先,为你的Python项目添加一个C扩展,不如,通过修改如下的 setup.py:
 

setup(
  ...
  ext_modules=[Extension('podpb',
sources=['cpp/podpb.c','cpp/main.pb.cc'], libraries=['protobuf'])],
  ...
  )

使用 protoc --cpp_out=cpp 生成main.pb.c, 并按如下所示创建 podpb.c 来设置一个空的 Python C 模块:
 

#include <Python.h>
 
static PyMethodDef PodMethods[] = {
 {NULL, NULL, 0, NULL}    /* Sentinel */};
 
PyMODINIT_FUNC
initpodpb(void)
{
 PyObject *m;
 
 m = Py_InitModule("podpb", PodMethods); if (m == NULL)  return;
}

现在就运行 python setup.py build 命令会构建所有的东西. 只要将C模块(在这里是podpb)导入到你的项目中,PB 运行时库就将会自动使用 C++ 实现了.

现在我们就分别有了68倍x 和 13倍 的速度提升. 吼吼.
 

$ PYTHONPATH=build/lib.linux-x86_64-2.6/:$PYTHONPATH \
> PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp \
> python sandbox/pbbench.py out.ini
ser: 6.39575719833e-06
parse: 4.55250144005e-05
msg size: 10730

我这篇文章发布到很多地方,大事完全忘了它的存在。同时 connex.io 和 Greplin 发布了他们的原生的 Python实现,cypb和fast-python-pb。cypb在PB的邮件列表中公布过,可以运行,但仍需要提升到可用的状态。fast-python-pb目前只支持string int32, int64 双精度浮点和子消息成员。除了这些项目,其他的我都不了解。你也可以查看我的orginal thread PB邮列表来了解到这些。

Python 相关文章推荐
python中使用urllib2伪造HTTP报头的2个方法
Jul 07 Python
python中django框架通过正则搜索页面上email地址的方法
Mar 21 Python
浅谈Python单向链表的实现
Dec 24 Python
Python实现快速计算词频功能示例
Jun 25 Python
python 读取文件并替换字段的实例
Jul 12 Python
python自动发送测试报告邮件功能的实现
Jan 22 Python
python实现AES和RSA加解密的方法
Mar 28 Python
Python实现线性判别分析(LDA)的MATLAB方式
Dec 09 Python
使用Keras预训练好的模型进行目标类别预测详解
Jun 27 Python
python代码能做成软件吗
Jul 24 Python
python实现图书馆抢座(自动预约)功能的示例代码
Sep 29 Python
Python实现信息轰炸工具(再也不怕说不过别人了)
Jun 11 Python
使用Python编写一个模仿CPU工作的程序
Apr 16 #Python
利用Python中的mock库对Python代码进行模拟测试
Apr 16 #Python
使用Python脚本来控制Windows Azure的简单教程
Apr 16 #Python
在Python下利用OpenCV来旋转图像的教程
Apr 16 #Python
在Python中使用Neo4j数据库的教程
Apr 16 #Python
使用Python的Zato发送AMQP消息的教程
Apr 16 #Python
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
Apr 16 #Python
You might like
用libTemplate实现静态网页的生成
2006/10/09 PHP
PHP加速 eAccelerator配置和使用指南
2009/06/05 PHP
PHP设置图片文件上传大小的具体实现方法
2013/10/11 PHP
PHP异常Parse error: syntax error, unexpected T_VAR错误解决方法
2014/05/06 PHP
微信公众平台网页授权获取用户基本信息中授权回调域名设置的变动
2014/10/21 PHP
Yii中CArrayDataProvider和CActiveDataProvider区别实例分析
2016/03/02 PHP
使用一个for循环将N*N的二维数组的所有值置1实现方法
2017/05/29 PHP
PHP基于自定义类随机生成姓名的方法示例
2017/08/05 PHP
js open() 与showModalDialog()方法使用介绍
2013/09/10 Javascript
ExtJS4 表格的嵌套 rowExpander应用
2014/05/02 Javascript
jQuery编程中的一些核心方法简介
2015/08/14 Javascript
jquery实现左右滑动菜单效果代码
2015/08/27 Javascript
vue子父组件通信的实现代码
2017/07/09 Javascript
微信小程序js文件改变参数并在视图上及时更新【推荐】
2018/06/11 Javascript
浅谈ECMAScript 中的Array类型
2019/06/10 Javascript
基于JavaScript获取base64图片大小
2019/10/18 Javascript
vue-dplayer 视频播放器实例代码
2019/11/08 Javascript
解析python实现Lasso回归
2019/09/11 Python
浅析matlab中imadjust函数
2020/02/27 Python
将pycharm配置为matlab或者spyder的用法说明
2020/06/08 Python
python 如何调用 dubbo 接口
2020/09/24 Python
基于Python爬取素材网站音频文件
2020/10/21 Python
如何基于Python和Flask编写Prometheus监控
2020/11/25 Python
Solaris操作系统的线程机制
2015/07/28 面试题
公务员职业生涯规划书范文  
2014/01/19 职场文书
文明青少年标兵事迹材料
2014/01/28 职场文书
集体备课反思
2014/02/12 职场文书
《祁黄羊》教学反思
2014/04/22 职场文书
教师党员个人整改措施
2014/10/27 职场文书
工会2014法制宣传日活动总结
2014/11/01 职场文书
2016干部作风整顿心得体会
2016/01/22 职场文书
Python基础之元组与文件知识总结
2021/05/19 Python
React-vscode使用jsx语法的问题及解决方法
2021/06/21 Javascript
SpringBoot集成Redis的思路详解
2021/10/16 Redis
Python多线程实用方法以及共享变量资源竞争问题
2022/04/12 Python
Go语言编译原理之源码调试
2022/08/05 Golang