Итерация по списку параллельно с Cython
Как выполняется параллельная итерация по списку (Python) в Cython?
рассмотрим следующую простую функцию:
def sumList():
cdef int n = 1000
cdef int sum = 0
ls = [i for i in range(n)]
cdef Py_ssize_t i
for i in prange(n, nogil=True):
sum += ls[i]
return sum
это дает много ошибок компилятора, потому что параллельный раздел без GIL, по-видимому, не может работать с любым объектом Python:
Error compiling Cython file:
------------------------------------------------------------
...
ls = [i for i in range(n)]
cdef Py_ssize_t i
for i in prange(n, nogil=True):
sum += ls[i]
^
------------------------------------------------------------
src/parallel.pyx:42:6: Coercion from Python not allowed without the GIL
Error compiling Cython file:
------------------------------------------------------------
...
ls = [i for i in range(n)]
cdef Py_ssize_t i
for i in prange(n, nogil=True):
sum += ls[i]
^
------------------------------------------------------------
src/parallel.pyx:42:6: Operation not allowed without gil
Error compiling Cython file:
------------------------------------------------------------
...
ls = [i for i in range(n)]
cdef Py_ssize_t i
for i in prange(n, nogil=True):
sum += ls[i]
^
------------------------------------------------------------
src/parallel.pyx:42:6: Converting to Python object not allowed without gil
Error compiling Cython file:
------------------------------------------------------------
...
ls = [i for i in range(n)]
cdef Py_ssize_t i
for i in prange(n, nogil=True):
sum += ls[i]
^
------------------------------------------------------------
src/parallel.pyx:42:11: Indexing Python object not allowed without gil
2 ответов
Я не знаю, как это сделать. Список-это объект Python, поэтому используйте его __getitem__
метод требует GIL. Если вы можете использовать массив NumPy в этом случае, он будет работать. Например, если вы хотите выполнить итерацию по массиву A
значений с плавающей запятой двойной точности вы можете сделать что-то вроде этого:
cimport cython
from numpy cimport ndarray as ar
from cython.parallel import prange
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef cysumpar(ar[double] A):
cdef double tot=0.
cdef int i, n=A.size
for i in prange(n, nogil=True):
tot += A[i]
return tot
на моей машине для этого конкретного случая prange не делает его быстрее обычного цикла, но в других случаях он может работать лучше. Для большего как использовать prange см. документацию по адресуhttp://docs.cython.org/src/userguide/parallelism.html
можно ли использовать массив или нет, зависит от того, насколько вы изменяете размер массива. Если вам нужно много гибкости с размером, массив не будет работать. Вы также можете попробовать взаимодействовать с vector
класс на C++. Я никогда не делал этого сам, но здесь есть краткое описание того, как это сделать: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#nested-class-declarations
преобразуйте свой список в массив, если вам нужно какое-либо числовое значение, или bytearray, если значения ограничены от 0 до 255. Если вы храните что-либо кроме числовых значений, попробуйте numpy или используйте dtypes напрямую. Например, с байтами:
cdef int[::1] gen = array.array('i',[1, 2, 3, 4])
и если вы хотите использовать C типа:
ctypedef unsigned char uint8_t