2017-07-02 49 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