10

如何在 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
4

2 回答 2

8

我不知道有什么方法可以做到这一点。列表是一个 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上的文档

您是否可以使用数组取决于您更改数组大小的程度。如果您需要很大的大小灵活性,则该数组将不起作用。您还可以尝试与vectorC++ 中的类进行交互。我自己从来没有这样做过,但是这里有一个关于如何做到这一点的简要描述:http: //docs.cython.org/src/userguide/wrapping_CPlusPlus.html#nested-class-declarations

于 2013-07-23T20:25:34.397 回答
1

如果您需要任何数值,则将列表转换为数组,如果值限制在 0 到 255 之间,则转换为 bytearray。如果您存储的不是数值,请尝试 numpy 或直接使用 dtypes。例如字节:

cdef int[::1] gen = array.array('i',[1, 2, 3, 4])

如果你想使用 C 类型:

ctypedef unsigned char uint8_t

于 2015-05-22T18:05:00.750 回答