了解使用Cython Extension类型与Python类的好处

时间:2017-10-02 01:12:21

标签: python cython

我是Cython的新手,在浏览Cython文档后,我遇到了Cython Extention types 。我想知道它对普通Python类有什么好处?我试图将我之前在其数据成员中具有列表的Python类转换为Cython扩展类型,但似乎我不能将列表声明为扩展类型中的数据成员。我唯一能做的就是将使用原始C数据类型的数据成员的Python类转换为Cython扩展类型。

我在Python类中有一段代码需要使用Cython进行优化。如何在不将类声明为Cython扩展类型的情况下Cython化与该段相关的函数? (基本上我只想将某些函数声明为cdef,而不是全部。)

2 个答案:

答案 0 :(得分:2)

在Cython中编写代码时,我没有使用过那些cdef ed类,所以我会将这部分留给cdef ed类型的好处让其他人回答。

在列表方面,虽然您仍然可以正常使用Python列表,但您需要copy each member explicitly into a C array来充分利用C语言编写的加速功能。但是,如果数据存储在一个NumPy数组,你可以只存储一个指向数组开头的指针(确保数组是C-连续的)。可以在此处找到NumPy和C类型的完整等价表:https://github.com/cython/cython/blob/master/Cython/Includes/numpy/__init__.pxd

至于cythonising类方法,因为大多数Python代码可以在Cython中无需修改就可以正常工作,你可以像往常一样使用class SomeClass:在Cython中定义你的类。由于cdef函数只能在Cython中调用,因此您可能希望在类外部定义cython化方法(最好键入以提高性能)。在类中,您可以使用常规def(可以从Python调用)来调用它们的cythonised对应项。

对于较大的Python类,你不想进入Cython,你可以使用类似的方法,但在Cython中只有def ed函数调用cdef ed版本。然后,您可以像导入模块时通常那样从Python调用Cython函数。

对于只需要驻留在C中而不与Python交互的数据结构,您可能还需要考虑使用PyCapsule将它们存储为类属性。

修改

通过阅读 chrisb 的答案下的评论,我认为你想拥有一个可变行长的二维数组。在深入研究在C中实现完全相同的数据结构之前,值得注意的是C不是Python。它不会自动为您管理列表的长度,而是您必须自己管理内存(请参阅第一个链接中的示例)。虽然这是动态分配内存的标准方式,但C(和Cython)新手的程序员往往不想触摸" malloc和朋友"因为指针会飞来飞去。最重要的是,C阵列通常没有混合数据类型,例如,你不能在同一个数组中同时包含数字和字符串(如果真的需要,有一种方法可以做到这一点。)

鉴于此,您可能希望重新考虑您的数据结构。例如,您可以考虑使用常量长度的数组来表示数据。如果您的阵列具有最大宽度,则可以使用NumPy阵列轻松编程来交换内存。

如果您乐意尝试手动内存管理,这里有一个为int的2D数组分配内存的简单示例:

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free

cdef int **generate_2D_array(int rows, int columns):
    cdef int row
    cdef int **parent = <int **>PyMem_Malloc(rows * sizeof(int*))
    if not parent:
        raise MemoryError()
    for row in range(rows):
        parent[row] = <int *>PyMem_Malloc(columns * sizeof(int))
        if not parent[row]:
            raise MemoryError()
    return parent

要更改行的长度,您可以使用:

cdef void resize_row(int *row_pointer, int new_size):
    PyMem_Realloc(row_pointer, new_size)

完成数据后,请记住使用PyMem_Free以与PyMem_Malloc分配类似的方式释放内存。经验法则是:对于您使用的每个PyMem_Malloc,只使用一个PyMem_Free释放内存,不多也不少。最后,只是一句警告,未能正确使用这些可能会导致分段错误,内存泄漏或未定义的行为。

答案 1 :(得分:0)

对于python-heavy操作,由于优化的字段访问和python开销删除,cdef类仍然会有一些性能优势。简单的例子:

0

这是以简单/调试能力为代价的,因此可能值得也可能不值得。更好的用例是当你想要存储和使用某些c级值时,性能优势可能会更加显着。