This page looks best with JavaScript enabled

Cython混合编程(1)

 ·  ☕ 3 min read · 👀... views

0x00 为什么需要Cython

  1. 如果已经阅读过我之前写的 多线程、协程与高并发 博文,或者对CPython解释器、GIL锁有一定了解,那肯定知道Python中的多线程是“假 多线程”,即cpu在同一时刻里只运行一条线程的运算,其他线程处于等待状态。而在C语言中不存在这个问题,因此用C语言和Python语言混合编程,可以很好的将两者的优点相结合。
  2. 数据的局部性原理:当使用C的时候,更多的数据可以塞进CPU的cache中,因为Python的元素都是Object,而每个Object都是通过字典实现的,cache对这个数据不很友好。并且对于计算机而言,他们对代码的运行速度是越低级的代码运行速度越快,而Python是高级语言,若想要将其提速,那可以将其编译为更为低级的机器码,Cython就是做这样的过程。
  3. 用Cython可简化python调用c语言程序的繁琐封装过程,提高python代码执行速度
  4. 在业界主流的几种Python扩展支持C语言的方案(ctypes,swig,cython)中,以c语言程序性能为基准的话,cython封装后下降20%,swig封装后下降70%。功能方面,swig对结构体和回调函数都要使用typemap进行手工编写转换规则,typemap规则写起来略复杂,体验不是很好。cython在结构体和回调上也要进行手工编码处理,不过比较简单。

0x01 安装Cython

重要的事情说一遍:Cython包 != cython包 !!!

在安装Cython前,需先安装Visual Studio Build Tools 和 Windows SDK

源码包安装

wget https://pypi.python.org/packages/b7/67/7e2a817f9e9c773ee3995c1e15204f5d01c8da71882016cac10342ef031b/Cython-0.25.2.tar.gz
tar xzvf Cython-0.25.2.tar.gz
cd Cython-0.25.2
python setup.py install

PIP安装

sudo pip install Cython --install-option="--no-cython-compile"

当看到类似这样的输出,则说明安装成功

C:\Users\87924>cython
Cython (http://cython.org) is a compiler for code written in the
Cython language.  Cython is based on Pyrex by Greg Ewing.

Usage: cython [options] sourcefile.{pyx,py} ...

Options:
  -V, --version                  Display version number of cython compiler
  -l, --create-listing           Write error messages to a listing file
  -I, --include-dir <directory>  Search for include files in named directory
                                 (multiple include directories are allowed).
  -o, --output-file <filename>   Specify name of generated C file
  -t, --timestamps               Only compile newer source files
  -f, --force                    Compile all source files (overrides implied -t)
  -v, --verbose                  Be verbose, print file names on multiple compilation
  -p, --embed-positions          If specified, the positions in Cython files of each
                                 function definition is embedded in its docstring.
  --cleanup <level>              Release interned objects on python exit, for memory debugging.
                                 Level indicates aggressiveness, default 0 releases nothing.
  -w, --working <directory>      Sets the working directory for Cython (the directory modules
                                 are searched from)
  --gdb                          Output debug information for cygdb
  --gdb-outdir <directory>       Specify gdb debug information output directory. Implies --gdb.

0x02 简单使用

然后,我们按照惯例来一个hello world了解一下大致的编译流程

1. 编写以 .pyx为扩展名的 cython程序

# hello.pyx

print("hello world!")

pyx可以理解为python代码和C代码的连接桥梁。在这里可以将python中的对象转化为C的变量,也可将C的变量转化为Python的对象。

2.编写python程序

# setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("hello.pyx")
)

这个文件用于编译刚刚写好的.pyx文件拓展,可将其编译封装为可导入的库。

3.执行setup.py编译拓展

python setup.py build_ext --inplace

build_ext参数差不多是编译extension的意思,而 –inplace 参数则是将编译结果输出到当前目录。编译完成后,会生成一个hello.c文件和一个hello.pyd文件(用PyObject* 封装好的库文件,若在Linux下编译则会生成hello.so) 我们需要将这个.pyd或.so文件和python脚本放在同一目录下,以便在Python脚本中使用import命令进行导入。

还看到有些方案是用pyximport模块直接将pyx文件在python脚本中导入,看似省去了编译这一步,实则却是非常危险的行为。如果在导入过程中,因为环境问题导致pyx导入失败,那整个程序就会崩溃,因此我还是赞成手动编译拓展的方法。

4.用python调用拓展

# t.py
import hello
hello.say("world")

运行结果:

PS C:\Users\87924\Desktop\source\_posts> python -u "c:\Users\87924\Desktop\source\_posts\t.py"
Hello world!

0x03 参考资料

  1. https://www.jianshu.com/p/fc5025094912
  2. https://cython.org/
  3. https://www.imooc.com/article/50834
  4. https://blog.csdn.net/yapingxin/article/details/80541537
  5. https://www.cnblogs.com/yuwentims/articles/9382884.html
Share on

Qfrost
WRITTEN BY
Qfrost
CTFer, Anti-Cheater, LLVM Committer