今天,我们来解决python的`速度`问题.我们平时所说的Python是指在PC机上的CPython,换句话说,Python的解释器是用C语言编写的.
为Python编写C扩展模块能够显著提高Python的执行速度,眼下有好几种方案可以完成这件事。
1. 使用Python自带的 ctypes 模块在Python内直接调用C的动态链接库代码,这对于调用现有的库,一些不开源的库很有用.
2. 用Python自带的c API来写模块,当然是用c/c++来编写
3. 用 Cython 的新语法来写扩展模块,这种新语法看起来既像Python又像C,是个语法混合体,但还有很多人推崇, 其优点是可以同时调用C函数和Python函数。但其语法小编着实看着头大,有兴趣的可以自行研究.
4. 用wsig, sip, boost.python等这些老派方法,他们都有各自的专门的要求,小编没用过,就不妄下评论了。
5. 使用pybind11来写Python扩展模块。这个好东西小编一定说几句,很值得一看,它只有头文件,用些简单的写法就可以封装C/C++的代码,待编译出动态链接库后,Python可以直接导入使用,小编曾在Mac OSX系统上写过pyOF库,封装了一个开源C++库的一部分代码,后来就没有时间弄了。推荐pybind11啊,它用来封装C++非常方便,大家可以到网上搜索一下。
6. 使用 cffi 模块。它本是pypy的一部分,pypy就是一个高速版Python,这个cffi也支持CPython, 它是ctypes的替代方案,在Python内写C代码和调用C动态库代码,但是比ctypes更方便,干净。
我们这里介绍的就是cffi, 它也是做 pyTorch 人工智能编程时官方推荐的使用方法。下面提供两段代码,分别是纯python编写,和使用cffi编写,算法都一样,函数做10000次递归,再重复1000次。
对比一下他们的执行速度。
======================= 纯 python 代码 =========================
# coding:utf-8
import sys
sys.setrecursionlimit(10010)
def factorial(n):
'Compute a factorial of n'
if n<=0:
return 1
else:
return n + factorial(n-1)
if __name__=='__main__':
for i in range(1000):
factorial(10000)
===================cffi 版本的 Python 代码 =========================
# coding:utf-8
from cffi import FFI
ffibuilder = FFI()
ffibuilder.cdef("unsigned long factor_cffi(unsigned long);")
ff = ffibuilder.verify(r'''
static unsigned long factor_cffi(unsigned long n) {
if(n <= 0) {
return 1;
}else{
return factor_cffi(n-1) + n;
}
}
''')
if __name__=='__main__':
for i in range(1000):
ff.factor_cffi(10000)
==================== 运行时间对比 =================
[Running] python "/home/xxx/dev/python/test.py"
[Done] exited with code=0 in 9.829 seconds
[Running] python "/home/xxx/dev/python/test_cffi.py"
[Done] exited with code=0 in 0.14 seconds
以上代码是在 Ubuntu 16 ,python 2.7下测试.
我们可以看到这个例子中,使用cffi模块混入红色的 C 代码编程,使效率提升70倍,当然算法不同,参数不同都会引发对比结果的大幅变动,并不是绝对的,这个仅仅是给大家一个直观的感受.
从以上代码就可以看出来,我们仅仅是混合了两种语言,并不需要学习第三方的专有语法,就可以调用C代码。当然cffi不止这一种用法。这里只给出一个最为直观的用法, 它运行时会在后台调用c编译器,我们也看不到编译过程。前提是你的机器上已经安装有C/C++编译器工具,python需安装cffi模块.
在众多方法中,网上有评测显示 cff i并不是最快速的方法. 最接近原生Pytohn C API的方法才是提速最快的方法,但使用 Pytohn C API 的方法实在是很麻烦地,所以说,根据不同的场景选择最合适的就是最好的。
对C语言,追求简单,上手快, 不用多学习, 懒人...... 我推荐 cffi,
对C++语言,第三方C++库, 我推荐 pybind11。


