先从一个例子来说,一个斐波那契数列数列例子说起:
# fib.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fib(i):
a = 0
b = 1
while i > 0:
i -= 1
a, b = b, a+b
return True
# try_c.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
from fib import fib
startTime = time.time()
for i in xrange(1,10):
fib(10**6)
print time.time() - startTime
在 CPython 下执行效果如下:
➜ cython python try_c.py
429.003911972
换成 pypy 的话,效率会更高一些:
(pypy)➜ cython pypy try_c.py
355.186796904
能不能有更快的效率呢?Python 的执行效率确实令人诟病,如果有 Python 的编写速度,C 的执行效率更好了(你说的是 Golang 嘛?)。这就是需要 Cython 出场了。
执行下面的命令就可以安装 Cython 了:
pip install cython
然后编写一个 setup.py 文件:
# setup.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from distutils.core import setup
from Cython.Build import cythonize
setup(name ='cython app',
ext_modules = cythonize("fib.pyx"),
)
将 fib.py 文件重命名为 fib.pyx 文件,然后执行下面命令就可以了:
(pypy)➜ cython pypy setup.py build_ext --inplace
running build_ext
building 'fib' extension
cc -arch x86_64 -O2 -fPIC -Wimplicit -I/Developer/pypy/include -c fib.c -o build/temp.macosx-10.9-x86_64-2.7/fib.o
fib.c:58:9: warning: 'Py_OptimizeFlag' macro redefined
#define Py_OptimizeFlag 0
^
/Developer/pypy/include/pypy_macros.h:613:9: note: previous
definition is here
#define Py_OptimizeFlag PyPy_OptimizeFlag
^
1 warning generated.
cc -shared -undefined dynamic_lookup -arch x86_64 build/temp.macosx-10.9-x86_64-2.7/fib.o -o /Desktop/cython/fib.pypy-23.so
具体执行的代码如下:
cython fib.pyx
cc -arch x86_64 -O2 -fPIC -Wimplicit -I/Users/jetlee/Developer/pypy/include -c fib.c -o build/temp.macosx-10.9-x86_64-2.7/fib.o
cc -shared -undefined dynamic_lookup -arch x86_64 build/temp.macosx-10.9-x86_64-2.7/fib.o -o /Users/jetlee/Desktop/cython/fib.pypy-23.so
这里有个很奇怪的地方,cython 生成的是 so 文件,我的系统是 mac,shared library 是. dylib 文件,不过 cython 这里只认识 so 文件,所以自己不要自以为是的改名了…
(pypy)➜ cython pypy try_c.py
208.884904146
再测试一下 CPython 的结果:
(pypy)➜ cython python try_c.py
215.461463928
上面的结果不是同样条件测试的,会对结果有一定的影响。具体情况下的结果还请自行测试。
除了利用 Cython 外,还有其他几种方法用来加速,这个可以自行搜索一下,比如 cffi,具体不在这里赘述。我个人比较倾向于 Cython 的方法,这种方法可以实现无需修改代码的加速(如上),同样也可以实现更高效的代码级别编译,效率更高。但是缺点是绕不开 python 的 GIL 问题,具体的可以看一下 这篇文章 介绍 GIL 问题。