Ho una funzione C che mallocs() e popola una matrice 2D di float. "Restituisce" quell'indirizzo e la dimensione dell'array. La firma èPosso forzare un numdy ndarray a diventare proprietario della sua memoria?
int get_array_c(float** addr, int* nrows, int* ncols);
Voglio chiamarlo da Python, quindi uso i ctypes.
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
Non ho mai capito come specificare i tipi di argomento con i tipi. Tendo a scrivere solo un wrapper python per ogni funzione C che sto usando, e mi assicuro di avere i tipi giusti nel wrapper. L'array di float è una matrice in ordine di colonna maggiore e mi piacerebbe ottenerla come numpy.ndarray. Ma è piuttosto grande, quindi voglio usare la memoria allocata dalla funzione C, non copiarla. (Ho appena trovato questa roba PyBuffer_FromMemory in questa risposta StackOverflow: https://stackoverflow.com/a/4355701/3691)
buffer_from_memory = ctypes.pythonapi.PyBuffer_FromMemory
buffer_from_memory.restype = ctypes.py_object
import numpy
def get_array_py():
nrows = ctypes.c_int()
ncols = ctypes.c_int()
addr_ptr = ctypes.POINTER(ctypes.c_float)()
get_array_c(ctypes.byref(addr_ptr), ctypes.byref(nrows), ctypes.byref(ncols))
buf = buffer_from_memory(addr_ptr, 4 * nrows * ncols)
return numpy.ndarray((nrows, ncols), dtype=numpy.float32, order='F',
buffer=buf)
Questo sembra darmi un array con i valori giusti. Ma sono abbastanza sicuro che sia una perdita di memoria.
L'array non possiede la memoria. Giusto; per impostazione predefinita, quando la matrice viene creata da un buffer, non dovrebbe. Ma in questo caso dovrebbe. Quando l'array numpy viene cancellato, mi piacerebbe davvero che python liberasse la memoria buffer per me. Sembra che se potessi forzare owndata su True, dovrebbe farlo, ma owndata non è impostabile.
soluzioni insoddisfacenti:
sfruttare al chiamante di get_array_py() responsabile di liberare la memoria. È super fastidioso; il chiamante dovrebbe essere in grado di trattare questo array numpy come qualsiasi altro array numpy.
Copia l'array originale in un nuovo array numpy (con la sua memoria separata) in get_array_py, elimina il primo array e libera la memoria all'interno di get_array_py(). Restituisce la copia invece della matrice originale. Questo è fastidioso perché è una copia di memoria non necessaria.
C'è un modo per fare ciò che voglio? Non riesco a modificare la funzione C stessa, anche se potrei aggiungere un'altra funzione C alla libreria, se ciò è utile.
Questo suona come un mondo di dolore .. Penso che tu stia chiedendo [segfault hell] (http://xkcd.com/371/) – wim
Ho provato anche questo senza successo usando i ctype. Un modulo di estensione completo lo rende possibile ma è più un lavoro da scrivere. –