首页 文章

Cython迭代不带gil的numpy数组列表

提问于
浏览
4

我想迭代一个具有不同维度的numpy数组列表,并将它们传递给不需要GIL的cython函数:

# 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数组,以便我可以迭代它们没有gil?我对涉及malloc C指针/ Cython内存视图/我不知道的其他类型的建议持开放态度 .

请注意,每个numpy数组具有不同的行数,但是已知数组列表的长度 .

3 回答

  • 2

    您可以将两个形状 (3,) 数组传递给 function_with_loop_over_arrays :一个( array_starts ),其中包含指向 abc 的第一个元素的指针,以及一个包含 T1T2T3 的( arrays_rows )指针 .

    然后修改 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])
    
  • -2

    正如错误消息所示,如果没有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 做了相当多的工作,那么索引应该是微不足道的 .

  • 1

    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)
    

    会给你相同(有效)的结果 .

相关问题