Я относительно новичок в Python, и это моя первая попытка написать расширение для C.
Предыстория В моем проекте Python 3.X мне нужно загружать и анализировать большие двоичные файлы (10–100 МБ) для извлечения данных для дальнейшей обработки. Двоичный контент организован во фреймы: за заголовками следует переменный объем данных. Из-за низкой производительности в Python я решил использовать расширение C, чтобы ускорить загрузку.
Автономный код C превосходит Python в 20-500 раз, поэтому я им вполне доволен.
Проблема: память продолжает расти, когда я несколько раз вызываю функцию из своего C-расширения в одном и том же модуле Python.
my_c_ext.c
#include <Python.h>
#include <numpy/arrayobject.h>
#include "my_c_ext.h"
static unsigned short *X, *Y;
static PyObject* c_load(PyObject* self, PyObject* args)
{
char *filename;
if(!PyArg_ParseTuple(args, "s", &filename))
return NULL;
PyObject *PyX, *PyY;
__load(filename);
npy_intp dims[1] = {n_events};
PyX = PyArray_SimpleNewFromData(1, dims, NPY_UINT16, X);
PyArray_ENABLEFLAGS((PyArrayObject*)PyX, NPY_ARRAY_OWNDATA);
PyY = PyArray_SimpleNewFromData(1, dims, NPY_UINT16, Y);
PyArray_ENABLEFLAGS((PyArrayObject*)PyY, NPY_ARRAY_OWNDATA);
PyObject *xy = Py_BuildValue("NN", PyX, PyY);
return xy;
}
...
//More Python C-extension boilerplate (methods, etc..)
...
void __load(char *) {
// open file, extract frame header and compute new_size
X = realloc(X, new_size * sizeof(*X));
Y = realloc(Y, new_size * sizeof(*Y));
X[i] = ...
Y[i] = ...
return;
}
test.py
import my_c_ext as ce
binary_files = ['file1.bin',...,'fileN.bin']
for f in binary_files:
x,y = ce.c_load(f)
del x,y
Здесь я удаляю возвращенные объекты в надежде снизить использование памяти.
Прочитав несколько сообщений (например, это, это и это), я все еще застрял.
Я пытался добавить/удалить PyArray_ENABLEFLAGS
, установив флаг NPY_ARRAY_OWNDATA
, но не заметил никакой разницы. Мне пока не ясно, подразумевает ли NPY_ARRAY_OWNDATA
free(X)
в C. Если я явно освобождаю массивы в C, я сталкиваюсь с segfault
при попытке загрузить второй файл в цикле for в test.py
.
Есть идеи, что я делаю неправильно?