Je développe un client qui recevra les données [EEG] sur TCP et écrivez-la sur la mémoire tampon d'anneau. Je pensais que cela peut être très pratique d'avoir le tampon en tant que CTTYPES ou une matrice numpue, car il est possible de créer une "vue" numpue à n'importe quel emplacement de ce tampon et de lecture / écriture / traiter les données sans opérations de copie. Ou est-ce une mauvaise idée en général? P>
Cependant, je ne vois pas comment implémenter un tampon circulaire d'une taille fixe de cette façon. Supposons que j'ai créé un objet tampon contigu en mémoire. Quelle est la meilleure façon d'écrire les données lorsque la fin du tampon est atteinte? P>
Un moyen possible est de commencer à écraser les octets (déjà anciens) du début lorsque le pointeur d'écriture atteint la fin de la matrice tampon. Près des limites, cependant, la vue générale de certains morceaux (pour la transformation) ne peut pas être créée (ou peut-il?) Dans ce cas, car une partie de celle-ci peut toujours être située à la fin de la matrice tampon tandis que d'autres déjà dans son début. J'ai lu qu'il est impossible de créer de telles tranches circulaires. Comment résoudre ce problème? P>
UPD: strong> Merci tout le monde pour les réponses. Au cas où quelqu'un est également confronté au même problème, ici '' s le code final que j'ai. p>
4 Réponses :
Un moyen possible est de commencer à écraser les octets (déjà anciens) du début lorsque le pointeur d'écriture atteint la fin de la matrice tampon. P>
C'est la seule option dans un tampon à anneau de taille fixe. P>
J'ai lu qu'il est impossible de créer de telles tranches circulaires. P> BlockQuote>
C'est pourquoi je ne ferais pas cela avec une vue engourdie. Vous pouvez créer une liste code> wrapper autour d'un
ndarray code> à la place du tampon / de la matrice, de la capacité et d'un pointeur (index) au point d'insertion. Si vous souhaitez obtenir le contenu sous forme de tableau NUMPY, vous devez effectuer une copie comme si: P>
buf = np.array([1,2,3,4]) indices = [3,0,1,2] contents = buf[indices] # copy
Merci. Mais, si ce morceau doit être copié de toute façon, il ne sera donc pas préférable d'utiliser des collections. ) code>? Ou est-ce beaucoup plus lent?
Je voulais éviter de copier parce que faire des fenêtres glissantes sur ces données signifiera la copie de presque la même pièce de données à chaque fois qu'un nouveau DataPoint arrive
@dmytro: Vous devrez mesurer si deque code> est plus rapide. Je crains que cela ne soit pas facile d'éviter de copier si vous souhaitez obtenir des données stockées par la mémoire tampon dans un tableau.
Si vous avez besoin d'une fenêtre de n octets, faites votre mémoire tampon 2 * N octets et écrivez toutes les entrées à deux emplacements: impression p> i% n code> et
i% n + n code> , où
i code> est un compteur d'octets. De cette façon, vous avez toujours N octets consécutifs dans le tampon.
Yepp. C'est ce que j'essaie d'écrire maintenant. Au lieu de 2 * N tampon, je possède une durée de la longueur arbitraire + N et suivez la même idée. Merci quand même!
C'est bien si la performance n'est pas une préoccupation du tout; Mais je doute que cela donne votre demande. Vous êtes probablement mieux en train d'utiliser une solution vectorisée à votre problème
Une variante de la réponse de @janne Karila, pour C mais pas Numpy: alors vous n'écrivez que des données une seule fois, et
Si la mémoire tampon d'anneau est très large, comme n x 1g, puis au lieu de doubler le tout,
Doubler un tableau de 2 * N pointres à ses rangées.
Par exemple. Pour n = 3, initialisez Anfuncunc (BUFP [J + 3]) code> voit les rangées dans
buf code> dans l'ordre de temps. p> p>
Je pense que vous devez prendre un recul de la pensée de style C ici. La mise à jour d'une ringbuffer pour chaque insertion ne sera jamais efficace. Un tampon à anneau est fondamentalement différent de l'interface de bloc de mémoire contiguë que la demande numpopie demande; Y compris la FFT que vous mentionnerez que vous voulez faire.
Une solution naturelle consiste à sacrifier un peu de mémoire pour des performances. Par exemple, si le nombre d'éléments que vous devez conserver dans votre tampon est N, allouez un tableau de N + 1024 (ou d'un nombre sensible). Ensuite, il vous suffit de déplacer n éléments autour de toutes les insertions de 1024, et vous avez toujours une vue contiguë de N éléments à agir directement disponible. P>
Edit: Voici un extrait de code qui implémente ce qui précède et devrait donner de bonnes performances. Notez cependant que vous seriez bien conseillé d'ajouter des morceaux, plutôt que par élément. Sinon, les avantages de performance de l'utilisation de NUMPY sont rapidement annulés, peu importe la manière dont vous implémentez votre Runbuffer. P>
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
Merci Eelco. Donc, une gamme de points de vue ne fonctionne tout simplement pas? Mais comment est-ce détecté et toute l'APTR remplacé par une copie à plat? APTR [0] .FLAGS a de la propriété fausse, déroutante.
Je ne suis pas sûr de ce que vous entendez par un éventail de vues; Les vues sont faciles à construire à la volée, vous n'avez donc pas besoin de les garder dans un tableau. Le creux de la question est que si vous cherchez à utiliser vos données comme une matrice numpue à tout moment, elle doit mentir en mémoire contiguë. Soit vous engagez une performance O (n) touchée à chaque fois que vous devez accéder à votre Ringbuffer contiguë après une annexe ou que vous devez attribuer une mémoire supplémentaire, vous pouvez donc retarder et amortir ces opérations nécessaires pour garder votre mémoire contiguë.
J'ai écrit le
numpy_ringbuffer code> paquet
pour résoudre ce problème, lequel fournit une interface code> deque code> à un tampon sous-jacent