Я думаю, вам нужно отступить от мышления в стиле C здесь. Обновление кольцевого буфера для каждой вставки никогда не будет эффективным. Кольцевой буфер принципиально отличается от непрерывного интерфейса блока памяти, который требуется для массивов; включая FFT, о котором вы говорите, что хотите сделать.
Естественное решение - пожертвовать небольшим количеством памяти ради производительности. Например, если количество элементов, которое вам нужно хранить в буфере, равно N, выделите массив из N + 1024 (или некоторого разумного числа). Тогда вам нужно всего лишь перемещать N элементов вокруг каждых 1024 вставок, и у вас всегда есть непрерывное представление о N элементах, чтобы действовать непосредственно на них.
РЕДАКТИРОВАТЬ: вот фрагмент кода, который реализует вышеупомянутое, и должен дать хорошую производительность. Тем не менее, обратите внимание, что вам будет лучше добавлять куски, а не по элементам. В противном случае преимущества производительности при использовании numpy быстро аннулируются, независимо от того, как реализован ваш кольцевой буфер.
import numpy as np
class RingBuffer(object):
def __init__(self, size, padding=None):
self.size = size
self.padding = size if padding is None else padding
self.buffer = np.zeros(self.size+self.padding)
self.counter = 0
def append(self, data):
"""this is an O(n) operation"""
data = data[-self.padding:]
n = len(data)
if self.remaining < n: self.compact()
self.buffer[self.counter+self.size:][:n] = data
self.counter += n
@property
def remaining(self):
return self.padding-self.counter
@property
def view(self):
"""this is always an O(1) operation"""
return self.buffer[self.counter:][:self.size]
def compact(self):
"""
note: only when this function is called, is an O(size) performance hit incurred,
and this cost is amortized over the whole padding space
"""
print 'compacting'
self.buffer[:self.size] = self.view
self.counter = 0
rb = RingBuffer(10)
for i in range(4):
rb.append([1,2,3])
print rb.view
rb.append(np.arange(15))
print rb.view #test overflow