Сбой Jupyter из-за использования PyArray_ENABLEFLAGS - PullRequest
0 голосов
/ 19 января 2019

Я пытаюсь преобразовать C double * в массив numpy на Cython, но пока не получилось. Я нашел эти полезные ссылки: Заставить NumPy ndarray стать владельцем памяти в Cython https://github.com/numpy/numpy/issues/8253

Но каждый раз, когда я использую следующий файл .pyx с Cython, это приводит к краху Jupyter (мертвое ядро):

.c файл:

#include<stdlib.h>
#include "test.h"

double* test1(int n) {
  double* A=(double*)calloc(n,sizeof(double));
  int i;
  for (i=0;i<n;i++) {
    A[i]=i+0.5; }
  return(A); }

Я также пытаюсь использовать malloc с тем же результатом.

.pyx файл:

cimport c_test
import numpy as np
cimport numpy as np

np.import_array()

ctypedef np.float64_t DTYPE_t

cdef extern from "numpy/arrayobject.h":
    void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)

cdef data_to_numpy_array_with_spec(void * ptr, np.npy_intp N, int t):
    cdef np.ndarray[DTYPE_t, ndim=1] arr = np.PyArray_SimpleNewFromData(1, &N, t, ptr)
    PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
    return arr

def test(n):
    cdef double* t1
    t=data_to_numpy_array_with_spec(c_test.test1(n),n,np.NPY_FLOAT64)
    return(t)

Функция c_fct.test1 возвращает C double * из n double, который я хочу преобразовать в пустой массив, которому принадлежат данные, чтобы избежать утечки памяти. Без строки PyArray_ENABLEFLAGS(t, np.NPY_ARRAY_OWNDATA) все работает нормально, но память не освобождается при уничтожении массива numpy.

блокнот Jupyter:

import cy_test as ct
ct.test(1000)

c_test.pxd file:

cdef extern from "test.h":
    double* test1(int n)

Мой файл setup.py выглядит так:

from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
import numpy as np

ext_modules = cythonize([Extension("cy_test", ["cy_test.pyx","test.c"])])


setup(
  name = 'Hello world app',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules,
  include_dirs=[np.get_include()]
)

Я думаю, что моя проблема может возникать по той же причине, что и в ссылке на github, но я не вижу, как ее решить (в моем случае указатель C уже существует, поэтому я думаю, что не могу использовать то же решение) .

Я работаю на Windows 10 с Anaconda 64bit, вот подробности версии: 3.7.1 (по умолчанию, 10 декабря 2018 г., 22:54:23) [MSC v.1915 64 бит (AMD64)]

Ответы [ 2 ]

0 голосов
/ 20 января 2019

Хорошо, благодаря вам, все готово, все, что мне нужно было сделать, это изменить файл .pyx следующим образом:

cimport c_test
import numpy as np
cimport numpy as np
from libc.stdlib cimport free

np.import_array()

ctypedef void (*PyCapsule_Destructor)(void*)

cdef extern from "numpy/arrayobject.h":
    void* PyCapsule_GetPointer(void* capsule, const char *name)
    void* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
    int PyArray_SetBaseObject(np.ndarray arr, void* obj)


cdef void capsule_cleanup(void* capsule):
    cdef void *memory = PyCapsule_GetPointer(capsule, NULL)
    free(memory)

def test(n):
  cdef np.ndarray arr
  cdef int nd = 1
  cdef np.npy_intp shape[1]
  shape[0] = <np.npy_intp> n
  cdef double *data = c_test.test1(n)
  arr = np.PyArray_SimpleNewFromData(nd, shape, np.NPY_DOUBLE, data)
  cdef void* capsule = PyCapsule_New(data, NULL, capsule_cleanup)
  PyArray_SetBaseObject( arr, capsule)
  return(arr)
0 голосов
/ 20 января 2019

Как объясняется в проблеме Github , которую вы связали, NPY_OWNDATA безопасно использовать только с памятью, выделенной через тот же распределитель, который использует сама NumPy.К этому распределителю можно получить доступ через функции PyDataMem_*.Если ваша память не поступает от этого распределителя, вы не можете использовать NPY_OWNDATA.

Не пытайтесь заставить массив вступать во владение произвольной памятью, которую вы ему предоставляете.Вместо этого установите base массива для объекта, который знает, как выполнить правильную очистку, используя PyArray_SetBaseObject. капсула может быть удобным объектом для использования.

...