2013-01-02 95 views
8

我想要編譯這種代碼2D名單:如何申報在用Cython

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列表。在google搜索「用Cython 2D名單」

+0

那麼,如果我離開聲明,我得到了編譯代碼,所以我猜我的聲明是錯誤的 – theta

+0

你真的想要列表或2d C數組? – delnan

+0

是的,就像它寫的。我試圖加速非常慢的Python代碼,該代碼循環遍歷這個(和另外兩個)列表的每個元素。試想一下,這是多麼緩慢。 – theta

回答

5
cdef double f[500][500] 

這是宣佈的500個雙打500℃陣列的C數組的文檔,我無法找到這樣一個例子。這是500 * 500打包的double值(在這種情況下存儲在堆棧中,除非Cython做了一些有趣的事情),沒有任何間接性,這有助於提高性能和緩存利用率,但顯然會增加嚴格的限制。也許你想要這個,但你應該學習足夠的C來首先知道這意味着什麼。順便說一下,一個限制是該大小必須是編譯時常量(取決於C版本; C99和C10允許),這是第一條錯誤消息的內容。

如果你確實使用數組,你不會像你所做的那樣初始化f,因爲這沒有任何意義。 f已經是500x500的雙變量,並且整個數組都不能被分配(這是後面的錯誤信息試圖告訴你的)。特別是,列表理解會創建一個完整的Python列表對象(您可以在Cython中使用,請參閱下文),其中包含完整的「盒裝」Python對象(在本例中爲float對象)。列表與C數組不兼容。對項目分配使用嵌套for循環進行初始化。最後,這樣一個數組需要500 * 500 * 8字節,這幾乎是2 MiB。在一些系統上,這比整個堆棧大,在所有其他系統上,它是如此大的一部分堆棧,這是一個壞主意。你應該堆 - 分配該數組。

如果您使用Python列表,請注意在性能和內存使用方面(假設您的代碼將主要操縱該列表),您不會獲得太多改進,儘管您可能獲得一些方便回報。你可以放棄cdef,或者使用list作爲類型(object也可以工作,但是你什麼也得不到,所以你可以省略它)。

一個NumPy數組可能會更快,更具有內存效率,更方便使用。如果您可以使用NumPy的操作來實現算法中性能至關重要的部分,那麼您可以在不使用Cython 的情況下獲得所需的加速比()。

+0

感謝您的解釋。我想我應該尋找C書的一面,同樣的建議漂浮只是通過瀏覽Cython文檔。所以在我學習更多關於C類型和操作的知識之前,我只是在這個例子中使用list。我認爲C數組應該更有效率,但是它們不能從Cython函數返回到Python代碼,而只是在Cython代碼中使用?目前加速只有3倍,但我會嘗試更進一步,首先使用Numpy和Cython,因爲只使用Numpy數組,而不會爲此示例代碼提高性能,如果它是相信的話。 – theta

8

不要在Cython中使用列表理解。有沒有加速,因爲他們創建常規的Python列表。維基says,你應該在用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

+0

感謝您的代碼片段,但當我看到'malloc'和類似術語時,我只是害怕。我還沒有去過,對我來說使用f2py更容易,但是很想從Cython開始很長時間。正如我回答,我現在將嘗試使用Cython和Numpy數組,而不是使用Cython和Python列表。謝謝 – theta