У меня умеренный опыт работы с Python и C, но я новичок в написании модулей Python в качестве оболочек для функций C. Для проекта мне нужна была одна функция с именем «Score», чтобы работать намного быстрее, чем я мог получить в python, поэтому я написал ее в C и буквально просто хочу иметь возможность вызывать ее из python. Он принимает список целых чисел в Python, и я хочу, чтобы функция C получала массив целых чисел, длину этого массива, а затем возвращала целое число обратно в Python. Вот мое текущее (рабочее) решение.
static PyObject *module_score(PyObject *self, PyObject *args) {
int i, size, value, *gene;
PyObject *seq, *data;
/* Parse the input tuple */
if (!PyArg_ParseTuple(args, "O", &data))
return NULL;
seq = PySequence_Fast(data, "expected a sequence");
size = PySequence_Size(seq);
gene = (int*) PyMem_Malloc(size * sizeof(int));
for (i = 0; i < size; i++)
gene[i] = PyInt_AsLong(PySequence_Fast_GET_ITEM(seq, i));
/* Call the external C function*/
value = score(gene, size);
PyMem_Free(gene);
/* Build the output tuple */
PyObject *ret = Py_BuildValue("i", value);
return ret;
}
Это работает, но, кажется, утечка памяти, и со скоростью, которую я не могу игнорировать. Я удостоверился, что утечка происходит в показанной функции, временно заставив функцию счета просто возвратить 0 и все еще видеть поведение утечки. Я думал, что вызов PyMem_Free должен заботиться о хранилище PyMem_Malloc, но мое текущее предположение состоит в том, что что-то в этой функции распределяется и сохраняется при каждом вызове, поскольку поведение утечки пропорционально количеству вызовов этой функции. Не правильно ли я выполняю преобразование последовательности в массив, или я неэффективно возвращаю конечное значение? Любая помощь приветствуется.
seq
это новый объект Python, поэтому вам нужно удалить этот объект. Вы должны проверить, если seq
тоже NULL.
Что-то вроде (не проверено):
static PyObject *module_score(PyObject *self, PyObject *args) {
int i, size, value, *gene;
long temp;
PyObject *seq, *data;
/* Parse the input tuple */
if (!PyArg_ParseTuple(args, "O", &data))
return NULL;
if (!(seq = PySequence_Fast(data, "expected a sequence")))
return NULL;
size = PySequence_Size(seq);
gene = (int*) PyMem_Malloc(size * sizeof(int));
for (i = 0; i < size; i++) {
temp = PyInt_AsLong(PySequence_Fast_GET_ITEM(seq, i));
if (temp == -1 && PyErr_Occurred()) {
Py_DECREF(seq);
PyErr_SetString(PyExc_ValueError, "an integer value is required");
return NULL;
}
/* Do whatever you need to verify temp will fit in an int */
gene[i] = (int*)temp;
}
/* Call the external C function*/
value = score(gene, size);
PyMem_Free(gene);
Py_DECREF(seq):
/* Build the output tuple */
PyObject *ret = Py_BuildValue("i", value);
return ret;
}