繁体   English   中英

Cython在没有gil的numpy数组列表上进行迭代

[英]Cython iterate over list of numpy arrays without the gil

我想遍历具有不同维数的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 memoryviews /其他我不知道的类型的建议。

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

您可以将两个形状为(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])  

如错误消息所述,没有gil,您将无法为Python list索引,并且实际上并没有任何明显的替代数据结构可以充当相同的角色。 您只需要移动nogil即可将索引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:块将索引放入a内。)

获取和发布gil成本很小,但前提是您的function_not_requiring_the_gil所做的工作量可观,而对其进行的索引编制却微不足道。

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)

将给您相同(有效)的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM