文章目录 一. Cython简介 一. Cython编译 2.1. 编译过程 2.2. 环境安装 2.3. disutils库 2.4. 引入C源文件 三. 总结 参考文献
一. Cython简介
Cython官网地址:https://cython.org/ Cython的下载和安装:https://pypi.org/project/Cython/
Cython是一个快速生成Python扩展模块的工具,从语法层面上来讲是 Python语法和C语言语法的混血 ,当Python性能遇到瓶颈时,Cython直接将C的原生速度植入Python程序,这样使Python程序无需使用C重写,能快速整合原有的Python程序,这样使得开发效率和执行效率都有很大的提高,而这些中间的部分,都是Cython帮我们做了。
一. Cython编译
因为Cython是 Python 的超集,所以 Python 解释器无法直接运行 Cython 的代码,那么如何才能将 Cython 代码变成 Python 解释器可以识别的有效代码呢?答案是通过 Cython 编译 Pipeline。 Pipeline 的职责就是将 Cython 代码转换成 Python 解释器可以直接导入并使用的 Python 扩展模块 ,这个 Pipeline 可以在不受用户干预的情况下自动运行(使 Cython 感觉像 Python 一样),也可以在需要更多控制时由用户显式的运行。
2.1. 编译过程
Pipeline由两步组成 :第一步 是由 cython 编译器负责将 Cython 转换成经过优化并且依赖当前平台的 C、C++ 代码;第二步 是使用标准的 C、C++ 编译器将第一步得到的 C、C++ 代码进行编译并生成标准的扩展模块,并且这个扩展模块是依赖特定的平台的。如果是在 Linux 或者 Mac OS,那么得到的扩展模块的后缀名为 .so ,如果是在 Windows 平台,那么得到的扩展模块的后缀名为 .pyd(扩展模块 .pyd 本质上是一个 DLL 文件) 。不管是什么平台,最终得到的都会是一个成熟的 Python 扩展模块,它是可以直接被 Python 解释器进行 import 的。
注意: Cython编译器是一种源到源的编译器,并且生成的扩展模块也是经过高度优化的,因此Cython生成的C代码编译得到的扩展模块比手写的C代码编译得到的扩展模块运行的要快并不是一件稀奇的事情。因为 Cython 生成的 C 代码是经过高度精炼,所以大部分情况下比手写所使用的算法更优 ,而且 Cython 生成的 C 代码支持所有的通用 C 编译器,生成的扩展模块同时支持许多不同的 Python 版本。
2.2. 环境安装
现在我们知道在编译 Pipeline 中有两个步骤,而实现这两个步骤需要我们确保机器上有 C、C++ 编译器以及 Cython 编译器 ,不同的平台有不同的选择。
C、C++编译器: Linux 和 Mac OS无需多说,因为它们都自带 gcc ,但是注意:如果是 Linux 的话,我们还需要 yum install python3-devel(以 CentOS 为例)。至于 Windows,可以下载一个 Visual Studio,但是那个玩意会比较大,如果不想下载 vs 的话,那么可以选择安装一个 MinGW 并设置到环境变量中,至于下载方式可以去https://sourceforge.net/projects/mingw/files/ 进行下载。
安装cython编译器 安装 cython 编译器的话,可以直接通过 pip install cython 即可。因此我们看到 cython 编译器只是 Python 的一个第三方包,因此运行 Cython 代码同样要借助 Python 解释器。
( allennlp_zkf) zkf@ubuntu: / data/ aibox/ kaifang/ trans/ cython$ cython - V
Cython version 0.29 .32
import Cython
print ( Cython. __version__)
2.3. disutils库
Python有一个标准库disutils ,可以用来构建、打包、分发 Python 工程 。而其中一个对我们有用的特性就是 它可以借助C编译器将C源码编译成扩展模块,并且这个模块是自带的、考虑了平台、架构、Python 版本等因素 ,因此我们在任意地方使用disutils都可以得到扩展模块。注意:上面 disutils 只是帮我们完成了 Pipeline 的第二步,那第一步呢?第一步则是需要 cython 来完成。
斐波那契数列 ,指的是这样一个数列:1、1、2、3、5、8、13、21、34、55、89
def fib ( n) : """ 这是一个扩展模块 """ cdef int icdef double a = 0.0 , b = 1.0 for i in range ( n) : a, b = a + b, areturn a
from distutils. core import setup
from Cython. Build import cythonize'''
我们说构建扩展模块的过程分为两步
1. 将Cython代码翻译成C代码;
2. 根据C代码生成扩展模块.
第一步要由cython编译器完成, 通过cythonize;
第二步要由distutils完成, 通过distutils.core下的setup'''
setup( ext_modules= cythonize( "fib.pyx" , language_level= 3 ) ) '''
cythonize负责将Cython代码转成C代码, 这里我们可以传入单个文件, 也可以是多个文件组成的列表
或者一个glob模式, 会匹配满足模式的所有Cython文件; 然后setup根据C代码生成扩展模块
'''
编译后产生的文件: 这个文件叫做 setup.py,这里只是做了准备,但是还没有进行编译。我们需要终端执行 python setup.py build 进行编译。在我们执行命令之后,当前目录会多出一个build目录,里面的结构如下。重点是那个fib.cpython-37m-x86_64-linux-gnu.so(windows系统的话就是.pyd结尾的)文件,该文件就是根据 fib.pyx 生成的扩展模块,至于其它的可以直接删掉了。我们把这个文件单独拿出来测试一下:
import fib
import tracebackprint ( fib)
print ( fib. fib( 20 ) )
print ( fib. fib. __doc__)
< module 'fib' from '/data/aibox/kaifang/trans/cython/fib.so' >
Traceback ( most recent call last) : File "/data/aibox/kaifang/trans/cython/test_fib.py" , line 16 , in < module> print ( fib. fib( "xx" ) ) File "fib.pyx" , line 14 , in fib. fibfor i in range ( n) :
TypeError: an integer is required55.0 这是一个扩展模块
2.4. 引入C源文件
除此之外我们还可以嵌入 C、C++ 的代码 ,我们来看一下。
double cfib ( int n) ;
double cfib ( int n) { int i; double a= 0.0 , b= 1.0 , tmp; for ( i= 0 ; i< n; ++ i) { tmp = a; a = a + b; b = tmp; } return a;
}
cdef extern from "cfib.h" : double cfib( int n)
def fib_with_c ( n) : """调用 C 编写的斐波那契数列""" return cfib( n)
from distutils. core import setup, Extension
from Cython. Build import cythonize
ext = Extension( name= "wrapper_cfib" , sources= [ "fib.pyx" , "cfib.c" ] )
setup( ext_modules= cythonize( ext) )
import wrapper_cfibprint ( wrapper_cfib. fib_with_c( 20 ) )
print ( wrapper_cfib. fib_with_c. __doc__)
6765.0
调用 C 编写的斐波那契数列Process finished with exit code 0
我们看到成功调用 C 编写的斐波那契数列,这里我们使用了一种新的创建扩展模块的方法,我们来总结一下。 如果是单个pyx文件的话, 那么直接通过 cythonize("xxx.pyx") 即可; 如果 pyx 文件还引入了 C 文件, 那么通过 cythonize(Extension(name="xx", sources=["", ""])) 的方式即可;name 是编译之后的扩展模块的名字, sources 是你要编译的源文件, 我们这里是一个 pyx 文件一个 C 文件;
建议后续都使用第二种方式,可定制性更强,而且我们之前使用的 cythonize("fib.pyx") 完全可以用 cythonize(Extension("fib", ["fib.pyx"])) 进行替代。
三. 总结
目前我们介绍了如何将 pyx 文件编译成扩展模块,对于一个简单的 pyx 文件来说,方法如下:
from distutils. core import setup, Extension
from Cython. Build import cythonize
ext = Extension( name= "wrapper_fib" , sources= [ "fib.pyx" ] ,
)
setup( ext_modules= cythonize( ext, language_level= 3 ) )
参考文献
Cython官网地址:https://cython.org/ 《Cython系列》2.编译并运行 Cython 代码的几种方式:https://www.cnblogs.com/traditional/p/13213173.html https://www.cnblogs.com/traditional/ https://www.jianshu.com/p/9053dacee822
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】 进行投诉反馈!