2013-07-23 11 views
8

Come si esegue un'iterazione in parallelo su un elenco (Python) in Cython?Iterazione su un elenco in parallelo con Cython

Si consideri il seguente semplice funzione:

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 

Questo dà un sacco di errori di compilazione, perché una sezione parallela senza il GIL a quanto pare non può funzionare con qualsiasi oggetto 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 
+1

Questo potrebbe non essere immediatamente utile, ma avete mai provato D? È sintassi c e cose come l'iterazione parallela sugli elenchi (array o intervalli in D) è quasi facile come farlo in MATLAB, se sei familiare. Guarda l'esempio qui: [std.parallelism] (http://dlang.org/phobos/std_parallelism). Ho trovato molto facile da ottenere da uno sfondo di Python. –

+0

@mattyTpain Non ho mai provato D, dare un'occhiata. – clstaudt

+0

@mattyTpain Sperimentato con D, è piaciuta la sintassi pythonic. Ma ecco un problema che ho riscontrato: http://stackoverflow.com/questions/17837098/parallel-iterators-in-the-d-language – clstaudt

risposta

6

io non sono consapevole di qualsiasi modo per farlo. Una lista è un oggetto Python, quindi usare il suo metodo __getitem__ richiede GIL. Se sei in grado di utilizzare un array NumPy in questo caso, funzionerà. Ad esempio, se si voleva iterare una matrice A di valori in virgola mobile a doppia precisione si potrebbe fare qualcosa di simile:

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 

Sulla mia macchina, per questo caso particolare, Prange non lo rende più veloce di qualsiasi un ciclo normale, ma potrebbe funzionare meglio in altri casi. Per ulteriori informazioni su come utilizzare prange consultare la documentazione al http://docs.cython.org/src/userguide/parallelism.html

Se è possibile utilizzare una matrice dipende o meno da quanto si sta modificando la dimensione della matrice. Se hai bisogno di molta flessibilità con le dimensioni, l'array non funzionerà. Puoi anche provare a interfacciare con la classe vector in C++. Non l'ho mai fatto da solo, ma c'è una breve descrizione di come farlo qui: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#nested-class-declarations

+0

D'altra parte, se hai solo bisogno di una somma, puoi anche solo usa il metodo 'sum' degli array NumPy. – IanH

+0

Grazie per i suggerimenti. La somma è solo un semplice esempio, ho bisogno di operazioni più complesse applicate in parallelo. – clstaudt

+0

Sì, nessun problema. – IanH

0

Converti la tua lista in una matrice se hai bisogno di un valore numerico, o un bytearray se i valori sono limitati tra 0 e 255 Se memorizzi qualcosa di diverso dai valori numerici, prova numpy o usa i dtypes direttamente. Per esempio con i byte:

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

E se si desidera utilizzare i tipi C:

ctypedef unsigned char uint8_t

Problemi correlati