У меня есть функция C, которая mallocs () и заполняет двумерный массив с плавающей точкой. Он «возвращает» этот адрес и размер массива. Подпись
int get_array_c(float** addr, int* nrows, int* ncols);
Я хочу вызвать его из Python, поэтому я использую ctypes.
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
Я так и не понял, как указать типы аргументов с помощью ctypes. Я обычно пишу оболочку Python для каждой функции C, которую я использую, и проверяю, правильно ли я получаю типы в оболочке. Массив с плавающей точкой - это матрица в порядке следования столбцов, и я хотел бы получить ее как numpy.ndarray. Но он довольно большой, поэтому я хочу использовать память, выделенную функцией C, а не копировать ее. (Я только что нашел этот материал PyBuffer_FromMemory в этом ответе 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)
Это, кажется, дает мне массив с правильными значениями. Но я уверен, что это утечка памяти.
>>> a = get_array_py()
>>> a.flags.owndata
False
Массив не владеет памятью. Справедливо; по умолчанию, когда массив создается из буфера, он не должен. Но в этом случае так и должно быть. Когда массив numpy удален, я бы очень хотел, чтобы python освободил для меня буферную память. Кажется, что если бы я мог принудительно установить owndata в True, он должен был бы это сделать, но owndata не устанавливается.
Неудовлетворительные решения:
Сделать так, чтобы вызывающая функция get_array_py () отвечала за освобождение памяти. Это супер раздражает; вызывающая сторона должна иметь возможность обрабатывать этот массив numpy так же, как и любой другой массив numpy.
Скопируйте исходный массив в новый массив numpy (со своей собственной, отдельной памятью) в get_array_py, удалите первый массив и освободите память внутри get_array_py (). Вернуть копию вместо исходного массива. Это раздражает, потому что это ненужная копия памяти.
Есть ли способ сделать то, что я хочу? Я не могу изменить саму функцию C, хотя могу добавить еще одну функцию C в библиотеку, если это будет полезно.