用Cython编译Python的C扩展
来源:互联网 发布:java什么是方法 编辑:程序博客网 时间:2024/06/13 10:22
然而用C写代码明显比Python麻烦多了,接口的处理也很繁琐,所以我一直没去尝试。
昨晚看到一篇《Cython三分钟入门》,让我眼前一亮:居然可以把大部分Python代码直接编译成C扩展(当然手动改写会更快,和C代码速度几乎完全相同)。而且它是完全自由的,可以使用任何许可证:public domain、BSD、GPL或all rights reserved。
不过介绍前首先得提下,我认为Python主要慢在这些地方:
变量类型在运行期动态决定,且可任意更改对象结构。这使得查找对象及其属性被延迟到运行期,而很多情况下是不会在运行期更改的,因此造成很大浪费。
一切都是对象,连整数也不例外,所以连整数加法都会构造新的对象,自然比C慢。因此涉及数值计算等大量计算的场合,使用NumPy、SciPy等C编写的库或自己编写C扩展比较好。
函数调用需要构造参数元组,开销比C大,而且也不会内联。但如果函数本身的运算时间很长,远大于函数调用的开销,那也没太多必要优化。
循环语句用for ... in xrange(...)是Python中最快的方法,但内部是用yield实现的,这种跳转代价很大,CPU很难预测。
如果认为自己的代码就慢在这几点,那么就继续往下看吧。
先是安装Cython。由于我只有Windows,所以就只介绍这个平台。
英文的说明可以看《InstallingOnWindows》,共有2步:
一、安装MinGW。现在SF已不提供完整安装版了,只能下载在线安装版。由于Cython也支持C++,所以我也勾选了g++编译器。
装好后把MinGW目录/bin加入PATH环境变量,并保证gcc --version可以正确执行。
接着去Python目录\Lib\distutils下添加一个distutils.cfg文件,内容如下:
[build]compiler = mingw32
实际上这最后一步也可不做,但每次编译都需要加一个-c参数来指定编译器。二、安装Cython。
我是直接下载exe版本的,直接运行即可。Python 2.4可能还要做些额外处理,我没有这个版本,没法测试。
接着就可以来测试了,先来写个hello world。
hw.py:
def hi(): print "Hello World"
setup.py:from distutils.core import setupfrom distutils.extension import Extensionfrom Cython.Distutils import build_extsetup( cmdclass = {'build_ext': build_ext}, ext_modules = [Extension("hw", ["hw.py"])])
然后运行这段代码进行编译:setup.py build_ext --inplace这就生成了很多文件,其中hw.pyd就是生成的C扩展了。
接着测试一下:
>>> from hw import hi
>>> hi()
Hello World
然后来测试下性能:
csigma.py和pysigma.py:
def sigma(n): a = 0 for i in xrange(n): a += i return a
测试脚本:from timeit import Timerprint Timer('sigma(10000)','from csigma import sigma').timeit(10000)print Timer('sigma(10000)','from pysigma import sigma').timeit(10000)
结果:3.97598186362提升了40%,不算太快。
5.50760753112
稍微改改csigma.py,加上变量类型声明:
def sigma(int n): # 这里也可以改成cpdef int sigma(int n),速度稍慢,看来要与Python交互的函数还是不要写返回值类型比较好;而加上inline则更慢 cdef int a = 0 cdef int i for i in xrange(n): # 也可写成for i from 0 <= i < n,实际上声明i为整数后,前者会自动转换成后者 a += i return a
这下提升就非常明显了:0.0740379014651此外,重命名为csigma.pyx,又变快了一点点,到了0.07以内了。
5.46775861178
接着和C比较一下,由于性能提高了很多,所以把计算参数改成一百万来测试。
先修改cygwinccompiler.py,把gcc -mno-cygwin -O改成gcc -mno-cygwin -O3(还可以改写setup.py,在Extension里加上extra_compile_args=["-O3"]),测试结果为6694~6709毫秒。
然后是C代码:
#include <stdio.h>#include <time.h>int sigma(int n){ int a = 0; int i = 0; // 循环变量也可以在for里声明,但必须加上-std=c99编译参数,而且会稍慢一点 for (; i < n; ++i) { a += i; } return a;}int main(){ clock_t t = clock(); int i = 0; int sum; for (; i < 10000; ++i) { sum = sigma(1000000); } clock_t t2 = clock(); printf("%d", t2 - t); printf("\n%d", sum); return 0;}
加上-O3参数,成绩为6671~6718毫秒,和Cython代码的速度几乎相同。2011年9月4日更新:Cython 0.15已经发布,cython -a指令可以显示哪些代码可以加上静态类型:
0 0
- 用Cython编译Python的C扩展
- 用Cython编译Python的C扩展
- 【转载】用Cython编译Python的C扩展
- Cython的编译方式
- 利用cython将python转为c代码
- 【Cython】用Cython包装C++代码,提供给python调用
- 使用 MinGW 编译 C/C++ 写的 python 扩展
- Python的C扩展
- Python扩展和嵌入: Cython三分钟入门(笔记)
- Python扩展和嵌入: Cython三分钟入门(笔记)
- cython,加速python,保护代码(3):扩展文件 .pxd
- 快速教程:使用Cython来扩展Python/NumPy库
- Python和C|C++的混编(二):利用Cython进行混编
- 【Cython】Cython包装C文件
- 使用cython保护python的代码
- 用c扩展python
- 用C语言扩展Python的功能
- 用C语言扩展Python的功能
- C++primer plus第六版课后编程题答案 6.7
- Socket编程之发送结构体报文
- 黑马程序员_多线程学习笔记
- Java Web编程中使用JSTL注意c标签URI引用
- html转义字符
- 用Cython编译Python的C扩展
- 祝愿开复老师早日恢复健康!
- Windows Server AppFabric缓存服务的几点实用心得
- 《黑马程序员》 Executors线程池的使用练习
- 共享内存是最快的一种IPC方式
- C++与Java的语法区别
- Java线程池使用
- jdbc
- Python扩展和嵌入: Cython三分钟入门(笔记)