如何在Cython中的(Python)列表上并行迭代?
考虑以下简单功能:
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
答案 0 :(得分:7)
我不知道有什么方法可以做到这一点。列表是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
上的文档是否可以使用数组取决于您更改数组大小的程度。如果您需要大小的灵活性,阵列将无法正常工作。您还可以尝试在C ++中与vector
类进行交互。我自己从未这样做过,但这里有一个简要的说明:http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#nested-class-declarations
答案 1 :(得分:0)
如果需要任何数值,请将列表转换为数组;如果值限制在0到255之间,则转换为bytearray。如果存储除数值以外的任何值,请尝试numpy或直接使用dtypes。例如,使用bytes:
cdef int[::1] gen = array.array('i',[1, 2, 3, 4])
如果你想使用C类型:
ctypedef unsigned char uint8_t