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:
- 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.
- 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.
- 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).
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
@ user3433489 Wie einfach! Ich habe nicht darüber nachgedacht ... – ead