Документация Cython по типизированным представлениям памяти перечисляет три способа присвоения типизированному представлению памяти:
- из необработанного указателя C,
- от
np.ndarray
и - из
cython.view.array
.
Предположим, что у меня нет данных, переданных в мою функцию cython извне, но вместо этого я хочу выделить память и вернуть ее в виде np.ndarray
, какой из этих вариантов я выбрал? Также предположим, что размер этого буфера не является константой времени компиляции, т.е. я не могу выделить его в стеке, но для варианта 1 потребуется malloc
.
Таким образом, 3 варианта будут выглядеть примерно так:
from libc.stdlib cimport malloc, free
cimport numpy as np
from cython cimport view
np.import_array()
def memview_malloc(int N):
cdef int * m = <int *>malloc(N * sizeof(int))
cdef int[::1] b = <int[:N]>m
free(<void *>m)
def memview_ndarray(int N):
cdef int[::1] b = np.empty(N, dtype=np.int32)
def memview_cyarray(int N):
cdef int[::1] b = view.array(shape=(N,), itemsize=sizeof(int), format="i")
Что меня удивляет, так это то, что во всех трех случаях Cython генерирует довольно много кода для выделения памяти, в частности, вызов __Pyx_PyObject_to_MemoryviewSlice_dc_int
. Это говорит о том (и я могу ошибаться, мое понимание внутренней работы Cython очень ограничено), что он сначала создает объект Python, а затем "встраивает" его в представление памяти, что кажется ненужным.
Простой бенчмарк не показывает большой разницы между тремя методами, причем 2. самый быстрый с небольшим отрывом.
Какой из трех методов рекомендуется? Или есть другой, лучший вариант?
Дополнительный вопрос: я хочу, наконец, вернуть результат в виде np.ndarray
, после работы с этим представлением памяти в функции. Является ли типизированное представление памяти лучшим выбором или я бы просто использовал старый интерфейс буфера, как ndarray
ниже, для создания ndarray
в первую очередь?
cdef np.ndarray[DTYPE_t, ndim=1] b = np.empty(N, dtype=np.int32)