【python开发技术】Cython 开发学习

Cython 开发学习

Posted by ZhangPY on April 6, 2020

【python开发技术】Cython 开发学习

使用Cython来进行Python C/C++交互

可以通过Cython编写python脚本,生成.c文件以及对应的python 的c extension package,用于加速python执行速度。

python有些慢的原因主要是啥都是运行时决定,而不是像C/C++编译时就决定了。而Cython采用python的脚本.pyx编写,通过cimport来引入.pxd文件,用@cython.boundscheck(False)和@cython.wraparound(False)两个修饰关闭边界检查,用cdef定义函数,可以定义返回值类型:

cdef int min(int x, int y):
    return x if x <=y else y

具体可以参考:

# 编写的cython .pyx文件
import numpy as np 
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
cdef np.ndarray[np.float32_t, ndim=2] _naive_dot(np.ndarray[np.float32_t, ndim=2] a, np.ndarray[np.float32_t, ndim=2] b):
    cdef np.ndarray[np.float32_t, ndim=2] c 
    cdef int n, p, m
    cdef np.float32_t s
    if a.shape[1] != b.shape[0]:
        raise ValueError('shape not matched')
    n, p, m = a.shape[0], a.shape[1], b.shape[1]
    c = np.zeros((n, m), dtype=np.float32)
    for i in range(n):
        for j in range(m):
            s = 0
            for k in range(p):
                s += a[i,k] * b[k,j]
            c[i,j] = s 
    return c 

def naive_dot(a, b):
    return _naive_dot(a, b)


# 编写的setup.py文件

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

import numpy
setup(ext_modules=cythonize(Extension(
    'dot_cython',
    sources=['dot_cython.pyx'],
    language='c',
    include_dirs=[numpy.get_include()],
    libraries=[],
    library_dirs=[],
    extra_compile_args=[],
    extra_link_args=[],
)))

调用命令:


python setup.py build_ext --inplace

会生成对应的dot_cython.cp36-win_amd64.pyddot_cython.c文件,即可实现调用。

对Cython程序进行分析

Cython的类型声明很重要,而不加类型声明也不会报错,会有可能漏加声明,Cython提供了工具进行分析:

cython -a dot_cython.pyx

而若当前Cython用到了C++,还需加上–cplus参数。

补充说明

Python 是很好的胶水语言,但是前提是库本身要使用 Python API 来和 Python 交互。有了 Cython 之后,我们可以照常编写 C/C++ 程序,或者是直接拿来一份已有的 C/C++ 源码,然后用 Cython 简单包装一下就可以使用了。

函数签名基本上可以原样从 C/C++ 复制到 Cython 中
C 中的 _Bool 类型和 C++ 中的 bool 类型在 Cython 中都用 bint 取代(因为 Python 没有布尔类型)
struct / enum / union 是支持的
const 限定和引用都是支持的
命名空间是支持的
C++ 类是支持的
部分操作符重载是支持的,部分操作符需要改名
内嵌类是支持的
模板是支持的
异常是支持的
构造函数、析构函数是支持的
静态成员是支持的
libc / libcpp / STL 是支持的
声明写在 .pxd 中可以在 .pyx 中 cimport 进来
你可能需要注意 Python 字符串到各式各样的 C/C++ 字符串的转换