Выравнивание памяти для быстрого БПФ в Python с использованием общих атрибутов

Я пишу приложение для обработки изображений, которое нужно делать несколько вещей, и оно должно делать их как можно больше в реальном времени. Приобретение данных и их обработка выполняется в отдельных процессах (в основном по соображениям производительности). Сами данные довольно большие (2-мегапиксельные 16-битные изображения в оттенках серого).

Я могу делиться массивами между процессами, как описано в этом сообщении: Как передать большие массивы numpy между подпроцессами python без сохранения на диск? (Я использую скрипт shmarray из пакета numpy-shared). Я могу выполнить поставляемый Nump FFT по этим данным без проблем, но это довольно медленно.

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

Вопрос: Есть ли способ создания и совместного использования массивов типа Numpy между процессами, которые в то же время гарантированно совпадают с памятью?

    Самый простой стандартный трюк, чтобы получить правильно выровненную память, состоит в том, чтобы выделить немного больше, чем нужно, и пропустить первые несколько байтов, если выравнивание неверно. Если я правильно помню, массивы NumPy всегда будут выровнены по 8 байт, а FFTW потребует 16-байтного алимента, чтобы лучше всего работать. Таким образом, вы просто выделите 8 байтов больше, чем нужно, и пропустите первые 8 байтов, если это необходимо.

    Изменить : это довольно просто реализовать. Указатель на данные доступен как целое число в ctypes.data массива NumPy. Использование сдвинутого блока может быть достигнуто путем нарезки, просмотра в виде другого типа данных и изменения формы – все это не будет копировать данные, а повторное использование одного и того же buf.

    Чтобы выделить 16-байтовый выровненный массив 1000×1000 из 64-битных чисел с плавающей запятой, мы могли бы использовать этот код:

     m = n = 1000 dtype = numpy.dtype(numpy.float64) nbytes = m * n * dtype.itemsize buf = numpy.empty(nbytes + 16, dtype=numpy.uint8) start_index = -buf.ctypes.data % 16 a = buf[start_index:start_index + nbytes].view(dtype).reshape(m, n) 

    Теперь a представляет собой массив с требуемыми свойствами, что можно проверить, проверяя, что a.ctypes.data % 16 действительно 0 .

    Обобщая ответ Sven, эта функция вернет выровненную копию (если необходимо) любого массива numpy:

     import numpy as np def aligned(a, alignment=16): if (a.ctypes.data % alignment) == 0: return a extra = alignment / a.itemsize buf = np.empty(a.size + extra, dtype=a.dtype) ofs = (-buf.ctypes.data % alignment) / a.itemsize aa = buf[ofs:ofs+a.size].reshape(a.shape) np.copyto(aa, a) assert (aa.ctypes.data % alignment) == 0 return aa