Расширение Python C OpenMP
Я получаю нарушение сегментации в интерпретаторе python при попытке получить доступ к переменной, которая возвращается моим собственным расширением OpenMP C++.
Все решения, которые я нашел, используют ctypes или cython (которые я не могу использовать). http://snatverk.blogspot.de/2012/03/c-parallel-modules-for-python.html показывает небольшой пример расширения Python с поддержкой OpenMP. Хотя я и пытался реализовать циклы for, как в примере, он все равно не работает.
Моя функция расширения кода выглядит следующим образом:
static PyObject *
matcher_match(PyObject *self, PyObject *args)
{
if(PyTuple_Size(args) != 2)
{
return NULL;
}
PyObject *names = PyTuple_GetItem(args, 0);
Py_ssize_t namesSize = PyList_Size(names);
PyObject *namesB = PyTuple_GetItem(args, 1);
Py_ssize_t namesBSize = PyList_Size(namesB);
PyObject *matchIdcs = PyList_New(namesSize);
Py_BEGIN_ALLOW_THREADS;
int i, j;
#pragma omp parallel for private(i, j)
for(i = 0; i < namesSize; i++)
{
for(j = 0; j < namesBSize; j++)
{
// test_pair_ij is a pure C function without callbacks into python
// it only uses the C++ STL like std::vector
float a = PyFloat_AsDouble(PyList_GetItem(names, i));
float b = PyFloat_AsDouble(PyList_GetItem(namesB, j));
bool res = test_pair_ij(a, b)
PyObject *matchVal;
if(res)
{
matchVal = Py_BuildValue("i", j);
}
else
{
matchVal = Py_BuildValue("i", -1);
}
PyList_SetItem(matchIdcs, i, matchVal);
}
}
Py_END_ALLOW_THREADS;
return matchIdcs;
}
Функция matcher_match() получает два списка, имена и имена B. Я проверяю каждую комбинацию имен и имен B (их атрибутов с плавающей точкой) на предмет определенного условия, которое указывается функцией test_pair_ij(). Функция является чистой реализацией C(++), которая не вызывает обратный вызов в python.
Расширение C вызывается с помощью:
from matcher import match
# some random lists for this example
names = ['123', '231', ...]
namesB = ['342', ...]
matchResult = match(names, namesB)
import pandas as pd
mr = pd.Series(matchResult)
mr.to_csv('matchResult.csv')
Когда имена списков и имена B довольно малы, код работает нормально. Но с большими списками я не могу получить доступ к matchResult больше в коде Python. Когда я пытаюсь это сделать, я получаю нарушение сегментации (которое, я думаю, находится внутри интерпретатора python). Я перекомпилировал расширение C без openmp, и оно снова заработало, даже с большими списками.
Я предполагаю, что проблема в некоторой путанице в памяти переменных Python, к которым я получаю доступ из моего расширения. Это может быть связано с GIL, хотя я выпускаю и приобретаю его. Нужно ли в этом случае делать больше переменных закрытыми? Есть еще идеи по этому поводу?
РЕДАКТИРОВАТЬ: исправлены вызывающие аргументы функции test_pair_ij.
РЕДАКТИРОВАТЬ 2: исправлен код хранения matchIdcs
ОТВЕТ:
код освобождает GIL и вызывает PyList_SetItem(matchIdcs, i, matchVal); была изменена структура Python, что недопустимо (см. http://docs.cython.org/src/userguide/external_C_code.html).