Il y a probablement un malentendu: cette fonction ne renvoie pas un tableau C mais une tranche de mémoire. Vous ne devez pas me croire, vous pouvez le vérifier en supprimant nogil
et en appelant Cython. Dans le créé * .c-fichier que vous pouvez voir le C-signature de votre fonction, __Pyx_memviewslice
étant la partie importante:
static CYTHON_INLINE __Pyx_memviewslice __pyx_f_4file_array_test(CYTHON_UNUSED double *__pyx_v_x)
Ce point de vue de la mémoire est un objet Python, donc il doit être enregistré dans le collecteur des ordures et par conséquent, le verrou Global Interpreter est nécessaire - c'est la raison pour laquelle vous voyez le message d'erreur «Operation not allowed without gil».
Donc, vous avez au moins trois options:
- Est-il vraiment si important de le faire avec "nogil"? Si non, alors il suffit de le laisser tomber. C'est la solution la plus simple, l'inconvénient: vous pourriez perdre des performances. Utilisez un véritable tableau C, c'est-à-dire
int *res = (int *) malloc(2*sizeof(int))
. C'est rapide, l'inconvénient: vous devez gérer la mémoire par vous-même.
- Utilisez C++ et
std::vector<int>
, l'avantage est que vous n'avez plus besoin de gérer la mémoire, mais vous devrez passer en C++.
Une amélioration de la possibilité 1. est d'acquérir gil uniquement pour la dernière ligne, où il est nécessaire (cela ne fera pas beaucoup de différence pour cet exemple mais peut pour le code réel):
cdef inline int[:] array_test(double *x) nogil:
cdef int output[2]
output[0]=1
output[1]=9
with gil:
return output
OP Comme l'a proposé, une autre possibilité serait de changer la signature de la fonction à:
cdef inline void array_test(double *x, int[:] output) nogil:
L'astuce ici: la fuction array_test
ne crée plus la tranche de vue de mémoire résultante et n'a pas à l'enregistrer dans le garbage collector, ainsi "nogil" est possible.
Il y a quelques inconvénients mineurs, comme l'appel de array_test
devenir plus lourd et l'appelant doit avoir gil afin de créer l'affichage de la mémoire output
. Mais il a aussi l'avantage, que l'appelant peut déterminer dans quel type de structure de données le résultat devrait être stocké (tableau numpy ou peut-être quelque chose d'autre).
Merci d'avoir listé les options! Une autre façon de contourner le problème est de faire de la fonction un vide, et de lui faire modifier un tableau d'entrée vide supplémentaire. – user3433489
@ user3433489 How simple! N'a pas pensé à ça ... – ead