2015-08-28 26 views
5

Sto avendo un dizionario,Utilizzando un dizionario in Cython, soprattutto all'interno nogil

my_dict = {'a':[1,2,3], 'b':[4,5] , 'c':[7,1,2]) 

voglio utilizzare questo dizionario all'interno di una funzione di Cython nogil. Così, ho provato a dichiararlo come

cdef dict cy_dict = my_dict 

Fino a questo stadio va bene.

Ora ho bisogno di scorrere i tasti di my_dict e se i valori sono in elenco, scorrere su di esso. In Python, è abbastanza facile come segue:

for key in my_dict: 
     if isinstance(my_dict[key], (list, tuple)): 
      ###### Iterate over the value of the list or tuple 
      for value in list: 
       ## Do some over operation. 

Ma, dentro Cython, voglio implementare la stessa che anche all'interno nogil. Come, gli oggetti Python non sono permessi all'interno di nogil, io sono tutto bloccato qui.

with nogil: 
    #### same implementation of the same in Cython 

Qualcuno può aiutarmi per favore?

risposta

16

L'unica opzione davvero sensata è accettare che è necessario il GIL, sfortunatamente. C'è anche un'opzione meno sensata che coinvolge le mappe C++, ma potrebbe essere difficile da applicare per il tuo caso specifico.

È possibile utilizzare with gil: per riacquisire GIL. In questo caso è evidente un sovraccarico (le parti che usano GIL non possono essere eseguite in parallelo, e potrebbe esserci un ritardo in attesa del GIL). Tuttavia, se la manipolazione dizionario è un piccolo pezzo di un pezzo più grande di codice Cython questo non può essere troppo cattivo:

with nogil: 
    # some large chunk of computationally intensive code goes here 
    with gil: 
    # your dictionary code 
    # more computationally intensive stuff here 

L'altra opzione meno sensibile è quello di utilizzare le mappe C++ (lungo il lato altri standard C++ tipi di dati della libreria). Cython può avvolgerli e convertirli automaticamente. Per fare un esempio banale, sulla base di dati di esempio:

from libcpp.map cimport map 
from libcpp.string cimport string 
from libcpp.vector cimport vector 
from cython.operator cimport dereference, preincrement 

def f(): 
    my_dict = {'a':[1,2,3], 'b':[4,5] , 'c':[7,1,2]} 
    # the following conversion has an computational cost to it 
    # and must be done with the GIL. Depending on your design 
    # you might be able to ensure it's only done once so that the 
    # cost doesn't matter much 
    cdef map[string,vector[int]] m = my_dict 

    # cdef statements can't go inside no gil, but much of the work can 
    cdef map[string,vector[int]].iterator end = m.end() 
    cdef map[string,vector[int]].iterator it = m.begin() 

    cdef int total_length = 0 

    with nogil: # all this stuff can now go inside nogil 
     while it != end: 
      total_length += dereference(it).second.size() 
      preincrement(it) 

    print total_length 

(è necessario compilare questo con language='c++').

Lo svantaggio evidente di questo è che i tipi di dati all'interno del dict devono essere noti in anticipo (non può essere un oggetto Python arbitrario). Tuttavia, dato che non puoi manipolare oggetti Python arbitrari all'interno di un blocco nogil, sei comunque abbastanza limitato.

+0

Grazie. Fammi dare un'occhiata. Tipo di dati all'interno del dizionario, lo terrò come lista. Per la compilazione, posso seguire il normale modo Cython giusto? –

+0

Devi specificare la lingua come descritto [qui] (http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#specify-c-language-in-setup-py) ma altrimenti dovrebbe funzionare normalmente modo. – DavidW

+0

Oh, mi dispiace. Ho cancellato il commento, perché l'ho trovato funzionante. Mi spiace menzionare che –