2017-07-02 26 views
3

我想遍歷不同尺寸numpy的陣列的列表,然後將其傳入到不需要用Cython功能GIL:用Cython迭代numpy的數組列表不吉

# a has T1 rows and M columns 
a = np.array([[0.0, 0.1, 0.3, 0.7], 
       [0.1, 0.2, 0.1, 0.6], 
       [0.1, 0.2, 0.1, 0.6]]) 

# b has T2 rows and M columns 
b = np.array([[1.0, 0.0, 0.0, 0.0], 
       [0.1, 0.2, 0.1, 0.6]]) 

# c has T3 rows and M columns 
c = np.array([[0.1, 0.0, 0.3, 0.6], 
       [0.5, 0.2, 0.3, 0.0], 
       [0.0, 1.0, 0.0, 0.0], 
       [0.0, 0.0, 0.1, 0.0]]) 

array_list = [a, b, c] 
N = len(array_list) 

# this function works 
@cython.boundscheck(False) 
@cython.wraparound(False) 
cdef void function_not_requiring_the_gil(double[:, ::1] arr) nogil: 
    cdef int T = arr.shape[0] 
    cdef int M = arr.shape[1] 
    cdef int i, t 

    for t in range(T): 
     for i in range(M): 
      # do some arbitrary thing to the array in-place 
      arr[t, i] += 0.001 

# issue is with this function 
def function_with_loop_over_arrays(array_list, int N): 
    cdef int i 

    with nogil: 
     for i in range(N): 
      function_not_requiring_the_gil(array_list[i]) 

當我編譯用Cython代碼,我得到以下錯誤:

Error compiling Cython file: 
------------------------------------------------------------ 
... 
def function_with_loop_over_arrays(array_list, int N): 
    cdef int i 

    with nogil: 
     for i in range(N): 
      function_not_requiring_the_gil(array_list[i])             ^
------------------------------------------------------------ 

my_file.pyx:312:53: Indexing Python object not allowed without gil 

有另一種類型的數據結構,我可以代替使用Python列表來存儲這些numpy的陣列,這樣我就可以在它們之間迭代,而不吉爾?我打開涉及malloc C指針/ Cython memoryviews /其他類型,我不知道的建議。

請注意,每個numpy數組的行數不同,但數組列表的長度是已知的。

回答

1

可以傳遞形狀(3,)的兩個數組,以function_with_loop_over_arrays:一個(array_starts),其包含指向的abc,和一個(arrays_rows)第一元件,其包含T1T2T3

然後修改function_not_requiring_the_gil,使得它接收到的陣列的第一個元素和它的行數上的指針,並且你將能夠調用它在function_with_loop_over_arrays與:

for i in range(N): # N is 3 and should be passed to function_with_loop_over_arrays 
    function_not_requiring_the_gil(array_starts[i], array_rows[i]) 
+0

感謝downvote! –

+0

@ B.M。好吧,我添加了一條評論,解釋爲什麼我低估了你的答案。有什麼問題嗎? –

+0

非常感謝您的回答,它確實解決了我的問題,但需要修改nogil函數以採用不同的參數。我實際上有幾個我想在這個循環中調用的nogil函數,並且它們中的每一個都以多個數組作爲輸入,所以不得不爲每個原始數組傳遞兩個參數(開始指針和行數)這些函數的參數數量。有沒有什麼辦法可以讓我自己傳遞數組/記憶體視圖?如果不是,我會接受你的答案。 – user3570195

-2

nogil功能往往容易從numba控制:

import numba 
@numba.jit(nogil=True) 
def function_not_requiring_the_gil(arr): 
    T,N = arr.shape 
    for t in range(T): 
     for i in range(N): 
     # do some arbitrary thing to the array in-place 
     arr[t, i] += 0.001 

def function_with_loop_over_arrays(array_list) 
     for a in array_list: 
      function_not_requiring_the_gil(a) 

將給你相同的(有效)的結果。

+0

我不認爲這解決了我的問題。你提出的建議只需要一個numpy數組,而不是任意的數組列表。我擁有的nogil功能實際上要複雜得多,而且我有幾個。問題是我想在循環中將這些nogil函數在不同大小的numpy數組上調用。 – user3570195

+0

感謝您編輯答案,現在它似乎解決了我的問題。然而,我真的想知道是否有一種方法可以用cython而不是numba來完成,因爲我需要在循環中調用的nogil函數已經實現。 – user3570195

+0

好的。但我不知道Cython足以幫助你。 –

1

作爲錯誤消息指出,你不能索引一個沒有gil的Python list,並且沒有任何明顯的替代數據結構可以完成相同的角色。你只需要移動nogil採取索引外面

def function_with_loop_over_arrays(array_list, int N): 
    cdef int i 
    cdef double[:, ::1] tmp_mview 

    for i in range(N): 
     tmp_mview = array_list[i] 
     with nogil:   
      function_not_requiring_the_gil(tmp_mview) 

(等同於你可以把索引一個with gil:塊內代替。)

有一個小的成本來獲取和釋放gil但提供與索引相比,您的function_not_requiring_the_gil做的工作量不大,應該是微不足道的。

+0

感謝您的回答,我瞭解使用列表的問題,這就是爲什麼我要求另一種傳遞數組的方式。我想爲該循環釋放GIL,因爲我將傳入許多數組並希望使用多線程。答案@P。所提供的Camilleri更接近我所期待的。 – user3570195

+0

您仍然可以使用多線程。它會稍微慢一些,因爲它需要偶爾等待每個線程獲得GIL,但它仍然會給你預期的大部分速度。 – DavidW