2015-08-28 11 views
5

ein Wörterbuch habe,ein Wörterbuch in Cython Verwendung, insbesondere innerhalb nogil

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

Ich möchte in einem Cython nogil Funktion dieses Wörterbuch verwenden. Also, ich habe versucht, es als

cdef dict cy_dict = my_dict 

zu deklarieren. Bis zu diesem Zeitpunkt ist in Ordnung.

Jetzt muss ich über die Schlüssel von my_dict iterieren und wenn die Werte in der Liste sind, iterieren Sie darüber. In Python ist es ganz einfach wie folgt:

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. 

Aber innerhalb Cython, ich möchte das gleiche implementieren, dass auch innerhalb nogil. Da Python-Objekte in Nogil nicht erlaubt sind, stehe ich hier oben.

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

Kann mir bitte jemand helfen?

Antwort

16

Die einzige wirklich sinnvolle Option ist leider zu akzeptieren, dass Sie die GIL benötigen. Es gibt auch eine weniger sinnvolle Option für C++ - Maps, aber es kann schwierig sein, sie für Ihren speziellen Fall anzuwenden.

Sie können with gil: verwenden, um die GIL erneut zu erwerben. Hier ist offensichtlich ein Overhead (Teile, die die GIL verwenden, können nicht parallel ausgeführt werden, und es kann eine Verzögerung geben, die auf die GIL wartet). Wenn jedoch die Wörterbuch-Manipulation ein kleines Stück eines größeren Stück Cython Code ist, kann dies nicht allzu schlecht sein:

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

Die andere weniger sinnvolle Option ist C++ Karten zu verwenden (an der Seite von anderen C++ Standard Bibliotheksdatentypen). Cython kann diese umbrechen und automatisch konvertieren. Um ein triviales Beispiel geben, basierend auf Ihrem Beispiel Daten:

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 

(Sie müssen kompilieren dies mit language='c++').

Der offensichtliche Nachteil ist, dass die Datentypen innerhalb des Diktats im Voraus bekannt sein müssen (es kann kein beliebiges Python-Objekt sein). Da Sie jedoch keine beliebigen Python-Objekte in einem nogil-Block manipulieren können, sind Sie ohnehin ziemlich eingeschränkt.

+0

Danke. Lass mich einen Blick darauf werfen. Datentyp im Wörterbuch, ich werde es als Liste behalten. Zur Kompilierung kann ich dem normalen Cython-Weg folgen oder? –

+0

Sie müssen die Sprache wie beschrieben [hier] (http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#specify-c-language-in-setup-py) angeben, aber ansonsten sollte es normal funktionieren Weg. – DavidW

+0

Oh, tut mir leid. Ich habe den Kommentar gelöscht, weil ich es funktionierte. Entschuldigung zu erwähnen, dass –