Как получить доступ к массиву NumPy через Cython

1

Я пытаюсь понять, который является самым быстрым и безопасным способом доступа к массиву NumPy, переданному через Cython, коду C. У меня есть следующие файлы:

func.c:

typedef struct {
    int nr;                
    double *my_array;      
} my_struct;

my_struct grid;

void allocate(int n) {
    grid.nr = n;
    grid.my_array = (double*)malloc(grid.nr*sizeof(double));
}

void Cfunc1(double *array) {
    my_array = array;

    //e.g. operation on my_array..
    for (int i=0; i<n; i++) my_array[i] *= 0.1;
}

void Cfunc2(int n, double *array) {
    for (int i=0; i<n; i++) {
        my_array[i] = array[i];

    //e.g. operation on my_array..
    for (int i=0; i<n; i++) my_array[i] *= 0.1;

}

func_wrap.pyx:

cdef extern from "func.h":
    void myfunc1(double *)
    void myfunc2(int, double *) 
    void allocate(int)

def pyfunc1(int n, double[:] array):
    allocate(n)
    Cfunc1(&array[0])

def pyfunc2(int n, double[:] array):
    allocate(n)
    Cfunc2(n, &array[0])

setup.py:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import distutils
setup(cmdclass = {'build_ext': build_ext}, ext_modules = [Extension("func", ["func.c"])]) 

func.so производится с:

python setup.py build_ext --inplace

py_func.py:

import numpy
import func

arr = numpy.random.randn(10)
func.pyfunc1(arr)   # or func.pyfunc2(len(arr), arr)

Некоторые вопросы:

  1. Cfunc1() ли использовать Cfunc1() или Cfunc2()?

  2. Использование Cfunc2 означает, что данные копируются? Какой из них вы бы использовали?

  3. Теоретически, я бы сказал, что Cfunc1 не требует предыдущего malloc my_array, тогда как Cfunc2 должен его требовать. Вместо этого обе функции, похоже, работают без malloc можете ли вы сказать мне, почему?

Большое спасибо!

  • 1
    1) Вы говорите мне! timeit - ваш друг ... 2) Это зависит от того, что делает pyfunc (вам нужно изменить array ? Хотите ли вы изменить его на месте?) 3) Не могли бы вы показать нам, где вы объявляете my_array ?
Теги:
arrays
numpy
cython

1 ответ

0

Вы задаете вопрос, "нужно ли мне копировать содержимое массива при передаче массива в C-код". Ответ таков, что нет, но в некоторых случаях вы, возможно, захотите. В основном, если вы хотите каким-либо образом изменить содержимое, не нарушая исходный массив. Также в некоторых случаях было бы полезно скопировать некондигированный массив в смежный массив, прежде чем запускать вычислительно-интенсивный алгоритм данных. При этом ваш текущий код предполагает, что данные уже смежны, поэтому в несмежном случае он просто даст неправильный результат, скопирует или не будет копировать.

Если вы собираетесь использовать доступ указателей к массивам numpy, вы почти всегда хотите использовать double[::1] вместо double[:] чтобы cython вставлял шаг проверки ошибок, чтобы убедиться, что массив смежный.

Кроме того, если вы собираетесь копировать содержимое массива numpy в какую-либо другую структуру данных (например, ac-массив или блок памяти malloc), вам нужно объявить/выделить достаточно памяти для этого. Не видя, как объявлен и назначен my_array, нет способа узнать, как работает ваш код, но память должна быть где-то выделена.

  • 0
    Ранее я выделил my_array с помощью my_array = (double *) malloc ((n) * sizeof (double)). my_array принадлежит к глобальной структуре, но я не хотел добавлять эту деталь, чтобы сделать вопрос более общим. Допустим, у меня много my_array, некоторые из них будут использоваться только для чтения в C, тогда как другие будут использоваться для возврата значений в скрипт Python. Должен ли я принять другое поведение для них?
  • 0
    @mtazzari, нужно быть более конкретным. Не зная, чего вы пытаетесь достичь, трудно дать какие-либо рекомендации.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню