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

时间:2017-07-02 06:05:29

标签: python c numpy cython

我想迭代一个具有不同维度的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 个答案:

答案 0 :(得分:2)

您可以将两个形状(3,)数组传递给function_with_loop_over_arrays:一个(array_starts),其中包含指向a的第一个元素的指针,bc和一个(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])  

答案 1 :(得分:1)

正如错误消息所示,您无法在没有gil的情况下为Python var map = L.map("root").setView([42, -71], 7); L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '&copy <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors' }).addTo(map); var drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems); var drawControl = new L.Control.Draw({ edit: { featureGroup: drawnItems } }); map.addControl(drawControl); 编制索引,并且实际上并没有任何明显的替代数据结构可以填充相同的角色。您只需移动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做了大量工作,那么与索引相比应该是微不足道的。

答案 2 :(得分:-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)

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