Расширение 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).

0 ответов

Другие вопросы по тегам