2016-10-24 12 views
0

Я хочу освободить GIL для того, чтобы параллелировать цикл в цитоне, где разные фрагменты памяти просматриваются некоторой функцией внутри цикла. Код выглядит следующим образом:cython memoryviews slices без GIL

cpdef void do_sth_in_parallel(bint[:,:] input, bint[:] output, int D): 
    for d in prange(D, schedule=dynamic, nogil=True): 
      ouput[d] = some_function_not_requiring_gil(x[d,:]) 

Это не представляется возможным, так как выбор срез х [D ,:], кажется, требует GIL. Запустив cython -a, и используя обычный цикл, я получаю код, указанный ниже. Как это можно сделать в чистом C?

 __pyx_t_5.data = __pyx_v_x.data; 
     __pyx_t_5.memview = __pyx_v_x.memview; 
     __PYX_INC_MEMVIEW(&__pyx_t_5, 0); 
     { 
    Py_ssize_t __pyx_tmp_idx = __pyx_v_d; 
    Py_ssize_t __pyx_tmp_shape = __pyx_v_x.shape[0]; 
    Py_ssize_t __pyx_tmp_stride = __pyx_v_x.strides[0]; 
    if (0 && (__pyx_tmp_idx < 0)) 
     __pyx_tmp_idx += __pyx_tmp_shape; 
    if (0 && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) { 
     PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis 0)"); 
     __PYX_ERR(0, 130, __pyx_L1_error) 
    } 
     __pyx_t_5.data += __pyx_tmp_idx * __pyx_tmp_stride; 
} 

__pyx_t_5.shape[0] = __pyx_v_x.shape[1]; 
__pyx_t_5.strides[0] = __pyx_v_x.strides[1]; 
    __pyx_t_5.suboffsets[0] = -1; 

__pyx_t_6.data = __pyx_v_u.data; 
     __pyx_t_6.memview = __pyx_v_u.memview; 
     __PYX_INC_MEMVIEW(&__pyx_t_6, 0); 
     __pyx_t_6.shape[0] = __pyx_v_u.shape[0]; 
__pyx_t_6.strides[0] = __pyx_v_u.strides[0]; 
    __pyx_t_6.suboffsets[0] = -1; 
+0

Есть примеры 'nogil' в скомпилированном' numpy' и 'scipy' коде. Я предлагаю посмотреть, есть ли в файлах '.pyx'. – hpaulj

+0

numpy/numpy/random/mtrand/mtrand.pyx – hpaulj

+0

Я все еще не понимаю, почему операция вызова среза из memoryview, то есть x [d ,:] требует взаимодействия с python? – tammo

ответ

1

следующие работы для меня:

from cython.parallel import prange 

cdef bint some_function_not_requiring_gil(bint[:] x) nogil: 
    return x[0] 

cpdef void do_sth_in_parallel(bint[:,:] input, bint[:] output, int D): 
    cdef int d 
    for d in prange(D, schedule=dynamic, nogil=True): 
      output[d] = some_function_not_requiring_gil(input[d,:]) 

Две основные изменения, которые я должен был сделать, были x к input (потому что это предполагает его можно найти x как объект питона в глобальном масштабе), чтобы исправить ошибку

Преобразование в Python объект не допускается без Gil

и добавление cdef int d, чтобы заставить тип d и исправить ошибку

Принуждение из Python не допускается без GIL

(Я также создал пример some_function_not_requiring_gil, но я предполагаю, что это довольно очевидно,)

0

Решение, которое работает для меня:

Доступ срез массива с помощью

input[d:d+1, :] 

вместо

input [d,:] 

И пройти 2D массив.