Как получить список представлений памяти в Cython? - PullRequest
1 голос
/ 06 июля 2019

Моя функция принимает список массивов разного размера:

def function1(list list_of_numpy_arrays):

Сейчас я делаю:

cdef int[:] a_view = list_of_numpy_arrays[index]

Проблема в том, что я вынужден индексировать список большое количество раз, поэтому накладные расходы значительно увеличивают время (в 10 раз).Я ищу что-то вроде cdef int[:] a[5], где я могу иметь массив представлений памяти, чтобы я мог избежать накладных расходов при индексации списков Python.

Я также могу передать список списков, если естьрешение для этого.

def function2(list list_of_lists):

1 Ответ

3 голосов
/ 09 июля 2019

То, что вы ищете, на самом деле не возможно в Cython.Если вы хотите что-то, что работает хорошо, я, вероятно, создаю структуру C, которая содержит соответствующую информацию из обзора памяти, а затем использую это вместо этого.Это не очень элегантное решение, но оно даст аналогичную производительность при использовании представлений памяти;Я бы не рекомендовал делать это общим шаблоном, но если у вас есть одноразовая проблема, когда ваши данные требуют, то все в порядке.

cdef struct FakeMemoryView:
    int* data
    int stride
    int length

Если вы были готовы вызвать непрерывные запоминания C (int[::1])) тогда вы могли бы бросить stride, так как это будет известно как единое целое.Данные могут быть проиндексированы с помощью var.data[i*var.stride].В начале вашей функции вы перебираете свой список Python для создания массива этих FakeMemoryView s, затем с этого момента вы просто используете этот массив:

def function1(list list_of_numpy_arrays):
    assert len(list_of_numpy_arrays) == 5

    cdef FakeMemoryView new_list[5]

    # initialize the list
    cdef int[:] mview
    for i in range(5):
        mview = list_of_numpy_arrays[i]
        new_list[i].data = &mview[0]
        new_list[i].stride = mview.strides[0]
        new_list[i].length = mview.shape[0]

    # example access - zero the first lot of data
    for i in range(new_list[0].length):
        new_list[0].data[i*new_list[0].stride] = 0

Если вы не знаетедлина списка заранее, тогда вам нужно самим обработать память с помощью malloc и free.

Это решение не обрабатывает подсчеты ссылок для массивов Numpy - поэтому вы не должны разрешать Numpyмассивы, которые нужно освободить, удерживая FakeMemoryView s.Не храните ваш массив для более чем одного вызова функции и не начинайте удалять массивы из списка ввода.

...