簡體   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