9

我正在尝试编译这种代码:

def my_func(double c, int m):
    cdef double f[m][m]

    f = [[c for x in range(m)] for y in range(m)]
    ...

这引发了:

Error compiling Cython file:
------------------------------------------------------------
def grow(double alpha, double beta, double gamma, int m, int s):
    cdef double f[m][m]
                     ^
------------------------------------------------------------
test.pyx:6:22: Not allowed in a constant expression

之后我假设我不能在指定的地方使用变量,我尝试使用数值:

def my_func(double c, int m):
    cdef double f[500][500]

    f = [[c for x in range(500)] for y in range(500)]
    ...

但后来我得到:

Error compiling Cython file:
------------------------------------------------------------
    f = [[beta for x in range(500)] for y in range(500)]
     ^
------------------------------------------------------------
test.pyx:13:6: Assignment to non-lvalue 'f'

所以,我想知道如何在 cython 代码中声明和制作 2D 列表。我在谷歌搜索“cython 2D list”的文档中找不到这种示例

4

2 回答 2

9

不要在 Cython 中使用列表推导。没有加速,因为他们创建了常规的 python 列表。Wiki,您应该在 Cython 中使用动态分配,如下所示:

from libc.stdlib cimport malloc, free

def my_func(double c, int m):
    cdef int x
    cdef int y
    cdef double *my_array = <double *>malloc(m * m * sizeof(double))

    try:

        for y in range(m):
            for x in range(m):
                #Row major array access
                my_array[ x + y * m ] = c

        #do some thing with my_array

    finally:
       free( my_array )

但是如果你需要一个二维数组的 python 对象,建议使用NumPy

于 2013-01-02T09:54:35.400 回答
7
cdef double f[500][500]

这是声明一个包含 500 个 C 数组的 500 个双精度数组的 C 数组。那是 500 * 500 压缩的双精度值(在这种情况下存储在堆栈中,除非 Cython 做了一些时髦的事情),没有任何间接,这有助于性能和缓存利用率,但显然增加了严格的限制。也许你想要这个,但你应该先学习足够的 C 来了解这意味着什么。顺便说一句,一个限制是大小必须是编译时常量(取决于 C 版本;C99 和 C10 允许),这就是第一条错误消息的内容。

如果您确实使用了数组,则不会f按照您所做的方式进行初始化,因为这没有任何意义。f已经是 500x500 双变量,并且不能将整个数组分配给(这是后一个错误消息试图告诉您的内容)。特别是,列表推导创建了一个完整的 Python 列表对象(您也可以从 Cython 使用它,见下文),其中包含完整的“盒装”Python 对象(float在本例中为 objects)。列表与 C 数组不兼容。使用带有项目分配的嵌套for循环进行初始化。最后,这样的数组需要 500 * 500 * 8 字节,几乎是 2 MiB。在某些系统上,这比整个堆栈都大,而在所有其他系统上,它占堆栈的很大一部分,这是一个坏主意。

如果您使用 Python 列表,请注意您不会在性能和内存使用方面获得太多改进(假设您的代码将主要操作该列表),尽管您可能会获得一些便利作为回报。您可以省略cdef, 或list用作类型(object也应该工作,但您没有从中获得任何收益,所以您不妨省略它)。

NumPy 数组可能更快、更节省内存并且更方便使用。如果您可以根据 NumPy 的操作来实现算法的性能关键部分,那么您完全可以在不使用 Cython情况下获得所需的加速。

于 2013-01-02T09:54:32.123 回答