Cython将py代码转so方式

 

部分的Python代码并未用到其动态性,却为此多付出了很多时间,所以出于性能考虑就会改用C扩展来加速。
然而用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文件,内容如下:

 
  1. [build]

  2. compiler = mingw32

实际上这最后一步也可不做,但每次编译都需要加一个-c参数来指定编译器。
二、安装Cython
我是直接下载exe版本的,直接运行即可。Python 2.4可能还要做些额外处理,我没有这个版本,没法测试。

接着就可以来测试了,先来写个hello world。
hw.py:

 
  1. def hi():

  2. print "Hello World"

setup.py:

 
  1. from distutils.core import setup

  2. from distutils.extension import Extension

  3. from Cython.Distutils import build_ext

  4.  
  5. setup(

  6. cmdclass = {'build_ext': build_ext},

  7. ext_modules = [Extension("hw", ["hw.py"])]

  8. )

然后运行这段代码进行编译:

setup.py build_ext --inplace

这就生成了很多文件,其中hw.pyd就是生成的C扩展了。
接着测试一下:

>>> from hw import hi
>>> hi()
Hello World


然后来测试下性能:
csigma.py和pysigma.py:

 
  1. def sigma(n):

  2. a = 0

  3. for i in xrange(n):

  4. a += i

  5. return a

测试脚本:

 
  1. from timeit import Timer

  2.  
  3. print Timer('sigma(10000)','from csigma import sigma').timeit(10000)

  4. print Timer('sigma(10000)','from pysigma import sigma').timeit(10000)

结果:

3.97598186362
5.50760753112

提升了40%,不算太快。
稍微改改csigma.py,加上变量类型声明:

 
  1. def sigma(int n): # 这里也可以改成cpdef int sigma(int n),速度稍慢,看来要与Python交互的函数还是不要写返回值类型比较好;而加上inline则更慢

  2. cdef int a = 0

  3. cdef int i

  4. for i in xrange(n): # 也可写成for i from 0 <= i < n,实际上声明i为整数后,前者会自动转换成后者

  5. a += i

  6. return a

这下提升就非常明显了:

0.0740379014651
5.46775861178

此外,重命名为csigma.pyx,又变快了一点点,到了0.07以内了。

接着和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指令可以显示哪些代码可以加上静态类型:

 

 

 

 

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

一、环境准备
    安装cython,以及gcc编译环境
wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
pip install cython
yum install -y gcc python-devel
二、编写测试脚本
   test.py,内容如下
import os
def test():
   print  os.path.realpath('.')
三、将其拷贝到python系统路径
    /usr/lib/python2.7/site-packages/test
    在test目录下创建__init__.py, 与 test.py 的文件
    test.py 上面内容如上所示
四、脚本测试
python 
>>> import lyh.test
>>> lyh.test.test()
五、编译so文件
    以下操作均在 /usr/lib/python2.7/site-packages/test 路径下执行

cython test.py
gcc -c -fPIC -I/usr/include/python2.7/ test.c
gcc -shared test.o -o test.so

六、验证so文件的可用性
    1. 移除/usr/lib/python2.7/site-packages/test/test.py 文件,只保留 test.so文件
        test
        ├── __init__.py
        └── test.so
    2. 
python
>>> import test.test
>>> test.test.test()
    可以执行
    验证完成

七、第二种方式:使用setup.py 编译so

     上面是使用gcc将py编译成so,下面直接使用python自带的setup.py来编译so

1. 编写setup.py文件,位于/usr/lib/python2.7/site-packages/test,内容如下:
from distutils.core import setup
from Cython.Build import cythonize
setup(
    ext_modules = cythonize("test.py")
)
2.然后运行
setup.py build_ext --inplace

八、第三种方式

见:

python文件编译成so介绍 - 2.使用makefile将py文件编译成so文件并制作成rpm包,实现自动化

http://blog.csdn.net/linshenyuan1213/article/details/79298473
--------------------- 
作者:linyonghui1213 
来源:CSDN 
原文:https://blog.csdn.net/linshenyuan1213/article/details/72677246 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值