2017-10-11 5 views
2

Ich mag würde eine Cython Funktion zu schaffen, die ein Array liest und gibt ein Array. Diese Funktion wird von anderen cdef-Funktionen aufgerufen, nicht von python def-Funktionen. Hier ist was ich habe.Cython: C Funktion erstellen, die ein Array liefert

In meiner .pxd Datei:

cdef int[:] array_test(double *x) nogil 

In meiner .pyx Datei:

cdef inline int[:] array_test(double *x) nogil: 

    cdef int output[2] 
    output[0]=1 
    output[1]=9 

    return output 

Aber wenn ich kompilieren, erhalte ich die Fehlermeldung: "Operation nicht ohne gil erlaubt" Kann jemand bitte helfen?

Antwort

3

Wahrscheinlich gibt es ein Mißverständnis: diese Funktion nicht einen C-Array zurückkehrt, sondern eine Speicheransicht slice. Sie müssen mir nicht glauben, Sie können es überprüfen, indem Sie nogil löschen und Cython aufrufen. Im erstellt * .c-Datei können Sie die C-Signatur Ihrer Funktion sehen, __Pyx_memviewslice ist der wichtige Teil:

static CYTHON_INLINE __Pyx_memviewslice __pyx_f_4file_array_test(CYTHON_UNUSED double *__pyx_v_x) 

Dieser Speicher Ansicht ist ein Python-Objekt, also muss es in der Garbage Collector registriert werden und Daher wird die globale Interpreter-Sperre benötigt - das ist der Grund, warum Sie die "Operation nicht erlaubt ohne Gil" -Fehlermeldung sehen.

So haben Sie mindestens drei Möglichkeiten:

  1. Ist es wirklich so wichtig, es mit "nogil" zu tun? Wenn nicht, dann lass es einfach fallen. Es ist die einfachste Lösung, der Nachteil: Sie könnten Leistung verlieren.
  2. echten C-Array verwenden, d.h. int *res = (int *) malloc(2*sizeof(int)). Es ist schnell, der Nachteil: Sie müssen die Erinnerung selbst verwalten.
  3. Verwenden C++ und std::vector<int>, der Vorteil ist, dass Sie den Speicher nicht mehr nicht verwalten müssen, aber Sie werden zu c wechseln müssen ++.

Eine Verbesserung der Möglichkeit 1 ist gil nur für die letzte Zeile zu erwerben, wo es gebraucht wird (dies wird nicht viel Unterschied für dieses Beispiel machen, sondern könnte zum echten Code):

cdef inline int[:] array_test(double *x) nogil: 
    cdef int output[2] 
    output[0]=1 
    output[1]=9 
    with gil: 
     return output 

Wie OP vorgeschlagen hat, wäre eine weitere Möglichkeit, zu ändern, um die Signatur der Funktion:

cdef inline void array_test(double *x, int[:] output) nogil: 

Der Trick hier: die fuction array_test nicht mehr die resultierende Speicher Ansicht Scheibe erzeugt und muss nicht in der Garbage Collector registrieren, also „nogil“ möglich.

Es gibt einige kleinere Nachteile, wie der Aufruf von array_test wird umständlicher und der Aufrufer muss Gil haben, um die output Speicheransicht zu erstellen. Aber es hat auch den Vorteil, dass der Aufrufer bestimmen kann, in welcher Art von Datenstruktur das Ergebnis gespeichert werden soll (numpy array oder etwas anderes).

+0

Vielen Dank für die Auflistung der Optionen! Eine andere Möglichkeit, ein Problem zu umgehen, besteht darin, die Funktion als void zu definieren und ein zusätzliches leeres Eingabearray zu modifizieren. – user3433489

+0

@ user3433489 Wie einfach! Ich habe nicht darüber nachgedacht ... – ead