使用Protocol Buffers的C语言拓展提速Python程序的示例
ProtocolBuffers(类似XML的一种数据描述语言)最新版本2.3里,protoc—py_out命令只生成原生的Python代码。尽管PB(ProtocolBuffers)可以为C++语言生成快速解析和序列化代码,但是这种方式对于Python不适用,并且手动生成的已包装的代码需要非常大的维护工作。在讨论组里,这是一个常见的功能要求,由于一个必备的客户端组件—AppEngine(根据团队介绍名称为AppEngine),生成原生的Python代码有更高的优先级。
幸运的是,PB2.4版本中本地化代码已被提名,在svn的分支中已经可以下载,因此你能够使用快速的PB有一段时间了。(我们使用r352版本有一段时间了,还没有遇到任何问题。)PB团队一直不愿轻易指定任何发布日期,在我的威胁下,KentonVarda提到日期初步定在2011年初。
我没有在其它地方看见过这个文档,希望它能对其他人有所帮助.
如何做能让它快起来
安装好新的PB库之后并使用protoc--py_out=... 重新构建好你的PB之后,你需要在运行你的Python程序之前进行环境变量PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp的设置,以便于选择C++的,或者PB默认使用的Python实现.
就这样了!这至少就能在可以动态转化/序列化消息的PB运行时库用通用的C++代码了.(注意我们还没有生成任何C++代码.)
它能有多快呢?我编写了一个简单的程序来获得性能在我们的应用程序中的提升感观:
nruns=1000nwarmups=100xs=...#yourprotobufsdefser():return[x.SerializeToString()forxinxs]defparse(ys):foryinys: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'msgsize:',sum(len(y)foryinys)/len(ys)
以秒为单位,这段程序在我的桌面上给出了如下几个时间结果:
$pythonsandbox/pbbench.pyout.ini ser:0.000434461673101 parse:0.000602062404156 msgsize:10730 $PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp\ >pythonsandbox/pbbench.pyout.ini ser:2.86788344383e-05 parse:7.63910810153e-05 msgsize: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来设置一个空的PythonC模块:
#include<Python.h> staticPyMethodDefPodMethods[]={ {NULL,NULL,0,NULL}/*Sentinel*/}; PyMODINIT_FUNC initpodpb(void) { PyObject*m; m=Py_InitModule("podpb",PodMethods);if(m==NULL)return; }
现在就运行pythonsetup.pybuild命令会构建所有的东西.只要将C模块(在这里是podpb)导入到你的项目中,PB运行时库就将会自动使用C++实现了.
现在我们就分别有了68倍x和13倍的速度提升.吼吼.
$PYTHONPATH=build/lib.linux-x86_64-2.6/:$PYTHONPATH\ >PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp\ >pythonsandbox/pbbench.pyout.ini ser:6.39575719833e-06 parse:4.55250144005e-05 msgsize:10730
我这篇文章发布到很多地方,大事完全忘了它的存在。同时connex.io和Greplin发布了他们的原生的Python实现,cypb和fast-python-pb。cypb在PB的邮件列表中公布过,可以运行,但仍需要提升到可用的状态。fast-python-pb目前只支持stringint32,int64双精度浮点和子消息成员。除了这些项目,其他的我都不了解。你也可以查看我的orginalthreadPB邮列表来了解到这些。