Я пытаюсь понять, который является самым быстрым и безопасным способом доступа к массиву 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)
Некоторые вопросы:
Cfunc1()
ли использовать Cfunc1()
или Cfunc2()
?
Использование Cfunc2
означает, что данные копируются? Какой из них вы бы использовали?
Теоретически, я бы сказал, что Cfunc1
не требует предыдущего malloc
my_array
, тогда как Cfunc2
должен его требовать. Вместо этого обе функции, похоже, работают без malloc
можете ли вы сказать мне, почему?
Большое спасибо!
Вы задаете вопрос, "нужно ли мне копировать содержимое массива при передаче массива в C-код". Ответ таков, что нет, но в некоторых случаях вы, возможно, захотите. В основном, если вы хотите каким-либо образом изменить содержимое, не нарушая исходный массив. Также в некоторых случаях было бы полезно скопировать некондигированный массив в смежный массив, прежде чем запускать вычислительно-интенсивный алгоритм данных. При этом ваш текущий код предполагает, что данные уже смежны, поэтому в несмежном случае он просто даст неправильный результат, скопирует или не будет копировать.
Если вы собираетесь использовать доступ указателей к массивам numpy, вы почти всегда хотите использовать double[::1]
вместо double[:]
чтобы cython вставлял шаг проверки ошибок, чтобы убедиться, что массив смежный.
Кроме того, если вы собираетесь копировать содержимое массива numpy в какую-либо другую структуру данных (например, ac-массив или блок памяти malloc), вам нужно объявить/выделить достаточно памяти для этого. Не видя, как объявлен и назначен my_array, нет способа узнать, как работает ваш код, но память должна быть где-то выделена.
timeit
- ваш друг ... 2) Это зависит от того, что делаетpyfunc
(вам нужно изменитьarray
? Хотите ли вы изменить его на месте?) 3) Не могли бы вы показать нам, где вы объявляетеmy_array
?