初识Cython扩展
Cython是什么?
Cython是一种扩展Python的语言,提供了Python和C的综合功能,支持在C/C++代码中调用,通过支持给函数、变量和类声明类型来实现,这些类型声明让Cython能够将Python脚本调整为纯C性能。
The Cython language is a superset of the Python language that additionally supports calling C functions and declaring C types on variables and class attributes. This allows the compiler to generate very efficient C code from Cython code.
学习过程中使用的资料为《Python高性能》一书和官方文档: http://docs.cython.org/en/latest/#
安装Cython
我使用环境是Ubuntu 18.04、Python 3.7.3
1 | pip install Cython |
编译Cython扩展
新建一个hello.pyx的文件:
1 | (Dev) $ cat hello.pyx |
注意加上#cython: language_level=3
这一行,否则会报出警告:
1 | FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! |
使用Cython命令读取hello.pyx并生成hello.c文件:
1 | (Dev) $ cython hello.pyx |
使用命令行GCC
接下来使用GCC编译器将hello.c文件编译为Python的扩展模块,需要启动Python专门的编译选项:
1 | gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -lm -I /usr/local/python3/include/python3.7m -o hello.so hello.c |
关于其中的编译选项,可以查看相关的文档,fno-strict-aliasing
这个倒是第一次遇到,要研究一下:
- -fwrapv:
https://gcc.gnu.org/onlinedocs/gcc-7.4.0/gcc/Code-Gen-Options.html - -fno-strict-aliasing:
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
https://stackoverflow.com/questions/7298546/gcc-c-c-assume-no-pointer-aliasing
https://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html
https://stackoverflow.com/questions/1225741/performance-impact-of-fno-strict-aliasing
https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule
https://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
此时查看目录结构,可以看到已经生成了hello.so文件:
1 | $ tree -h |
该扩展模块可以直接在Python会话中导入使用:
1 | python |
使用distutils
distutils是标准的Python打包工具,可以更简单的编译Cython代码。在目录下新建一个简单的setup.py
脚本:
1 | (Dev) $ cat setup.py |
cythonize可接受一个字符串或字符串列表,其中包含要编译的Cython模块。
执行setup.py
脚本:
1 | (Dev) $ python setup.py build_ext --inplace |
选项build_ext
: 让脚本setup.py构建ext_modules中指定的扩展模块;
选项--inplace
: 让这个脚本将输出文件hello.so放在源文件所在的目录。
此时的目录结构:
1 | tree -h |
在Python会话中,同样可以看到和命令行GCC模式一样的效果。
使用pyximport
可以使用pyximport进行自动编译Cython模块,只需要在脚本中加入pyximport.install()
,在解释器中执行也是可以的:
1 | import pyximport |
但是该方法在同时涉及到C和Cython文件时就无法使用了。
使用Jupyter
Cython也可以被使用在Jupyter notebook中,首先安装Jupyter:
1 | pip install jupyter |
在Jupyter中加载Cython扩展:
1 | In[1]: %load_ext Cython |
可以使用%%cython标记为单元格添加前缀以编译它:
1 | In[2]: %%cython |
几种编译Cython的方法就学习到这啦,接下来准备学习一下静态类型的使用😄