effizienter kreisförmiger Puffer?


109

Ich möchte einen effizienten zirkulären Puffer in Python erstellen (mit dem Ziel, Durchschnittswerte der ganzzahligen Werte im Puffer zu ermitteln).

Ist dies eine effiziente Möglichkeit, eine Liste zum Sammeln von Werten zu verwenden?

def add_to_buffer( self, num ):
    self.mylist.pop( 0 )
    self.mylist.append( num )

Was wäre effizienter (und warum)?


Dies ist keine effiziente Methode zum Implementieren eines Ringpuffers, da pop (0) eine O (n) -Operation in der Liste ist. pop (0) entfernt das erste Element in der Liste und alle Elemente müssen nach links verschoben werden. Verwenden Sie stattdessen collection.deque mit dem Attribut maxlen. deque hat die O (1) -Operation für Anhängen und Pop.
Vlad Bezden

Antworten:


204

Ich würde collections.dequemit einem maxlenarg verwenden

>>> import collections
>>> d = collections.deque(maxlen=10)
>>> d
deque([], maxlen=10)
>>> for i in xrange(20):
...     d.append(i)
... 
>>> d
deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19], maxlen=10)

In den Dokumenten gibt es ein Rezeptdeque , das dem entspricht, was Sie möchten. Meine Behauptung, dass es das effizienteste ist, beruht ausschließlich auf der Tatsache, dass es in C von einer unglaublich erfahrenen Crew implementiert wird, die es sich zur Gewohnheit macht, erstklassigen Code herauszubringen.


7
+1 Ja, es sind die schönen Batterien. Operationen für den Ringpuffer sind O (1) und wie Sie sagen, ist der zusätzliche Overhead in C, sollte also immer noch ziemlich schnell sein
John La Rooy

7
Diese Lösung gefällt mir nicht, da die Dokumente keinen O (1) -Wahlzugriff garantieren, wenn sie maxlendefiniert sind. O (n) ist verständlich, wenn die dequeDose bis ins Unendliche wachsen kann, aber wenn maxlengegeben, sollte die Indizierung eines Elements eine konstante Zeit sein.
lvella

1
Ich vermute, dass es als verknüpfte Liste und nicht als Array implementiert ist.
E-Satis

1
Scheint ungefähr richtig, wenn die Zeiten in meiner Antwort unten korrekt sind.
DJVG

13

Wenn Sie vom Kopf einer Liste abspringen, wird die gesamte Liste kopiert und ist daher ineffizient

Sie sollten stattdessen eine Liste / ein Array mit fester Größe und einen Index verwenden, der sich beim Hinzufügen / Entfernen von Elementen durch den Puffer bewegt


4
Zustimmen. Egal wie elegant oder unelegant es aussehen mag oder welche Sprache auch immer verwendet wird. In Wirklichkeit ist es umso besser, je weniger Sie sich um den Garbage Collector (oder den Heap-Manager oder die Paging- / Mapping-Mechanismen oder was auch immer die eigentliche Speichermagie macht) kümmern.

@RocketSurgeon Es ist keine Magie, es ist nur ein Array, dessen erstes Element gelöscht wird. Für ein Array der Größe n bedeutet dies also n-1 Kopiervorgänge. Hierbei handelt es sich nicht um einen Garbage Collector oder ein ähnliches Gerät.
Christian

3
Genau. Dies ist auch viel einfacher als manche Leute denken. Verwenden Sie einfach einen ständig wachsenden Zähler und den Modulo-Operator (% arraylen), wenn Sie auf das Element zugreifen.
Andre Blum

idem, Sie können meinen Beitrag oben überprüfen, so habe ich es gemacht
MoonCactus

10

Basierend auf der Antwort von MoonCactus ist hier eine circularlistKlasse. Der Unterschied zu seiner Version besteht darin, dass hier c[0]immer das älteste angehängte Element angegeben wird.c[-1] das zuletzt angehängte Element, c[-2]das vorletzte ... angegeben wird. Dies ist für Anwendungen natürlicher.

c = circularlist(4)
c.append(1); print c, c[0], c[-1]    #[1]              1, 1
c.append(2); print c, c[0], c[-1]    #[1, 2]           1, 2
c.append(3); print c, c[0], c[-1]    #[1, 2, 3]        1, 3
c.append(8); print c, c[0], c[-1]    #[1, 2, 3, 8]     1, 8
c.append(10); print c, c[0], c[-1]   #[10, 2, 3, 8]    2, 10
c.append(11); print c, c[0], c[-1]   #[10, 11, 3, 8]   3, 11

Klasse:

class circularlist(object):
    def __init__(self, size, data = []):
        """Initialization"""
        self.index = 0
        self.size = size
        self._data = list(data)[-size:]

    def append(self, value):
        """Append an element"""
        if len(self._data) == self.size:
            self._data[self.index] = value
        else:
            self._data.append(value)
        self.index = (self.index + 1) % self.size

    def __getitem__(self, key):
        """Get element by index, relative to the current index"""
        if len(self._data) == self.size:
            return(self._data[(key + self.index) % self.size])
        else:
            return(self._data[key])

    def __repr__(self):
        """Return string representation"""
        return self._data.__repr__() + ' (' + str(len(self._data))+' items)'

[Bearbeitet]: Optionaler dataParameter hinzugefügt , um die Initialisierung aus vorhandenen Listen zu ermöglichen, z.

circularlist(4, [1, 2, 3, 4, 5])      #  [2, 3, 4, 5] (4 items)
circularlist(4, set([1, 2, 3, 4, 5])) #  [2, 3, 4, 5] (4 items)
circularlist(4, (1, 2, 3, 4, 5))      #  [2, 3, 4, 5] (4 items)

Gute Ergänzung. Python - Listen erlauben bereits negative Indizes, aber (-1), zB würde den erwarteten Wert nicht zurück , sobald der Ringpuffer voll ist, da die „letzte“ neben der Liste landet in der Liste.
MoonCactus

1
Es funktioniert @MoonCactus, siehe die 6 Beispiele, die ich oben auf der Antwort gegeben habe; In den letzten c[-1]ist immer das richtige Element zu sehen. __getitem__macht es richtig.
Basj

oh ja, ich meine meine ist gescheitert, nicht deine, sorry: DI wird meinen Kommentar klarer machen! - Oh, ich kann nicht, der Kommentar ist zu alt.
MoonCactus

schöne einfache Lösung. Ich habe ein optionales Argument hinzugefügt, um die Initialisierung der Liste aus vorhandenen Daten zu ermöglichen. Auf diese Weise ist es pythonpathischer.
Orwellophile

9

Pythons Deque ist langsam. Sie können stattdessen auch numpy.roll verwenden. Wie drehen Sie die Zahlen in einem numpy-Array der Form (n,) oder (n, 1)?

In diesem Benchmark beträgt die Deque 448 ms. Numpy.roll ist 29ms http://scimusing.wordpress.com/2013/10/25/ring-buffers-in-pythonnumpy/


1
Aber numpy.rollgibt eine Kopie des Arrays zurück, oder?
DJVG

3
Diese Antwort ist sehr irreführend - Pythons Deque scheint ziemlich schnell zu sein, aber das Konvertieren von und in numpy Arrays verlangsamt es in den Benchmarks, mit denen Sie verknüpfen, erheblich.
Xitrium

7

ok mit der Verwendung der Deque-Klasse, aber für die Anforderungen der Frage (Durchschnitt) ist dies meine Lösung:

>>> from collections import deque
>>> class CircularBuffer(deque):
...     def __init__(self, size=0):
...             super(CircularBuffer, self).__init__(maxlen=size)
...     @property
...     def average(self):  # TODO: Make type check for integer or floats
...             return sum(self)/len(self)
...
>>>
>>> cb = CircularBuffer(size=10)
>>> for i in range(20):
...     cb.append(i)
...     print "@%s, Average: %s" % (cb, cb.average)
...
@deque([0], maxlen=10), Average: 0
@deque([0, 1], maxlen=10), Average: 0
@deque([0, 1, 2], maxlen=10), Average: 1
@deque([0, 1, 2, 3], maxlen=10), Average: 1
@deque([0, 1, 2, 3, 4], maxlen=10), Average: 2
@deque([0, 1, 2, 3, 4, 5], maxlen=10), Average: 2
@deque([0, 1, 2, 3, 4, 5, 6], maxlen=10), Average: 3
@deque([0, 1, 2, 3, 4, 5, 6, 7], maxlen=10), Average: 3
@deque([0, 1, 2, 3, 4, 5, 6, 7, 8], maxlen=10), Average: 4
@deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10), Average: 4
@deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], maxlen=10), Average: 5
@deque([2, 3, 4, 5, 6, 7, 8, 9, 10, 11], maxlen=10), Average: 6
@deque([3, 4, 5, 6, 7, 8, 9, 10, 11, 12], maxlen=10), Average: 7
@deque([4, 5, 6, 7, 8, 9, 10, 11, 12, 13], maxlen=10), Average: 8
@deque([5, 6, 7, 8, 9, 10, 11, 12, 13, 14], maxlen=10), Average: 9
@deque([6, 7, 8, 9, 10, 11, 12, 13, 14, 15], maxlen=10), Average: 10
@deque([7, 8, 9, 10, 11, 12, 13, 14, 15, 16], maxlen=10), Average: 11
@deque([8, 9, 10, 11, 12, 13, 14, 15, 16, 17], maxlen=10), Average: 12
@deque([9, 10, 11, 12, 13, 14, 15, 16, 17, 18], maxlen=10), Average: 13
@deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19], maxlen=10), Average: 14

Ich bekomme TypeError: 'numpy.float64' object is not callablebeim Versuch, averageMethode
aufzurufen

Ja ... in der Tat denke ich, dass deque numpy Arrays intern verwendet (nach dem Entfernen von @property funktioniert es gut)
scls

17
Ich garantiere, dass deque intern keine Numpy-Arrays verwendet. collectionsist Teil der Standardbibliothek, numpynicht. Abhängigkeiten von Bibliotheken von Drittanbietern würden zu einer schrecklichen Standardbibliothek führen.

6

Obwohl es hier bereits viele gute Antworten gibt, konnte ich keinen direkten Vergleich der Timings für die genannten Optionen finden. Deshalb finden Sie unten meinen bescheidenen Versuch eines Vergleichs.

Nur zu Testzwecken kann die Klasse zwischen einem listPuffer auf Basis, einem collections.dequePuffer auf Basis und einem Numpy.rollPuffer auf Basis wechseln .

Beachten Sie, dass die updateMethode jeweils nur einen Wert hinzufügt, um dies einfach zu halten.

import numpy
import timeit
import collections


class CircularBuffer(object):
    buffer_methods = ('list', 'deque', 'roll')

    def __init__(self, buffer_size, buffer_method):
        self.content = None
        self.size = buffer_size
        self.method = buffer_method

    def update(self, scalar):
        if self.method == self.buffer_methods[0]:
            # Use list
            try:
                self.content.append(scalar)
                self.content.pop(0)
            except AttributeError:
                self.content = [0.] * self.size
        elif self.method == self.buffer_methods[1]:
            # Use collections.deque
            try:
                self.content.append(scalar)
            except AttributeError:
                self.content = collections.deque([0.] * self.size,
                                                 maxlen=self.size)
        elif self.method == self.buffer_methods[2]:
            # Use Numpy.roll
            try:
                self.content = numpy.roll(self.content, -1)
                self.content[-1] = scalar
            except IndexError:
                self.content = numpy.zeros(self.size, dtype=float)

# Testing and Timing
circular_buffer_size = 100
circular_buffers = [CircularBuffer(buffer_size=circular_buffer_size,
                                   buffer_method=method)
                    for method in CircularBuffer.buffer_methods]
timeit_iterations = 1e4
timeit_setup = 'from __main__ import circular_buffers'
timeit_results = []
for i, cb in enumerate(circular_buffers):
    # We add a convenient number of convenient values (see equality test below)
    code = '[circular_buffers[{}].update(float(j)) for j in range({})]'.format(
        i, circular_buffer_size)
    # Testing
    eval(code)
    buffer_content = [item for item in cb.content]
    assert buffer_content == range(circular_buffer_size)
    # Timing
    timeit_results.append(
        timeit.timeit(code, setup=timeit_setup, number=int(timeit_iterations)))
    print '{}: total {:.2f}s ({:.2f}ms per iteration)'.format(
        cb.method, timeit_results[-1],
        timeit_results[-1] / timeit_iterations * 1e3)

Auf meinem System ergibt dies:

list:  total 1.06s (0.11ms per iteration)
deque: total 0.87s (0.09ms per iteration)
roll:  total 6.27s (0.63ms per iteration)

4

Wie wäre es mit der Lösung aus dem Python-Kochbuch , einschließlich einer Neuklassifizierung der Ringpufferinstanz, wenn sie voll ist?

class RingBuffer:
    """ class that implements a not-yet-full buffer """
    def __init__(self,size_max):
        self.max = size_max
        self.data = []

    class __Full:
        """ class that implements a full buffer """
        def append(self, x):
            """ Append an element overwriting the oldest one. """
            self.data[self.cur] = x
            self.cur = (self.cur+1) % self.max
        def get(self):
            """ return list of elements in correct order """
            return self.data[self.cur:]+self.data[:self.cur]

    def append(self,x):
        """append an element at the end of the buffer"""
        self.data.append(x)
        if len(self.data) == self.max:
            self.cur = 0
            # Permanently change self's class from non-full to full
            self.__class__ = self.__Full

    def get(self):
        """ Return a list of elements from the oldest to the newest. """
        return self.data

# sample usage
if __name__=='__main__':
    x=RingBuffer(5)
    x.append(1); x.append(2); x.append(3); x.append(4)
    print(x.__class__, x.get())
    x.append(5)
    print(x.__class__, x.get())
    x.append(6)
    print(x.data, x.get())
    x.append(7); x.append(8); x.append(9); x.append(10)
    print(x.data, x.get())

Die bemerkenswerte Wahl für das Design in der Implementierung ist, dass ich dies durch Ändern modelliert habe, da diese Objekte zu einem bestimmten Zeitpunkt ihrer Lebensdauer einen nicht umkehrbaren Zustandsübergang durchlaufen - von nicht vollem Puffer zu vollem Puffer (und Verhaltensänderungen zu diesem Zeitpunkt) self.__class__. Dies funktioniert sogar in Python 2.2, solange beide Klassen dieselben Slots haben (z. B. funktioniert es gut für zwei klassische Klassen wie RingBuffer und __Fullin diesem Rezept).

Das Ändern der Klasse einer Instanz mag in vielen Sprachen seltsam sein, ist jedoch eine pythonische Alternative zu anderen Arten der Darstellung gelegentlicher, massiver, irreversibler und diskreter Zustandsänderungen, die das Verhalten stark beeinflussen, wie in diesem Rezept. Gut, dass Python es für alle Arten von Klassen unterstützt.

Bildnachweis: Sébastien Keim


Ich habe einige Geschwindigkeitstests gegen Deque durchgeführt. Dies ist ungefähr 7 mal langsamer als deque.
PolyMesh

@PolyMesh super, du solltest den Autor wissen lassen!
d8aninja

1
Was wäre der Sinn davon? Es ist ein altes veröffentlichtes Dokument. Der Sinn meines Kommentars ist es, andere wissen zu lassen, dass diese Antwort veraltet ist, und stattdessen deque zu verwenden.
PolyMesh

@PolyMesh es war wahrscheinlich noch langsamer, als er es veröffentlichte; Anweisungen zur Kontaktaufnahme mit dem Autor finden Sie im Intro des Buches. Ich beziehe nur eine mögliche Alternative. Außerdem: "Wenn nur Geschwindigkeit die beste Metrik wäre; leider kann es nur eine gute sein."
d8aninja

3

Sie können auch dieses ziemlich alte Python-Rezept sehen .

Hier ist meine eigene Version mit NumPy-Array:

#!/usr/bin/env python

import numpy as np

class RingBuffer(object):
    def __init__(self, size_max, default_value=0.0, dtype=float):
        """initialization"""
        self.size_max = size_max

        self._data = np.empty(size_max, dtype=dtype)
        self._data.fill(default_value)

        self.size = 0

    def append(self, value):
        """append an element"""
        self._data = np.roll(self._data, 1)
        self._data[0] = value 

        self.size += 1

        if self.size == self.size_max:
            self.__class__  = RingBufferFull

    def get_all(self):
        """return a list of elements from the oldest to the newest"""
        return(self._data)

    def get_partial(self):
        return(self.get_all()[0:self.size])

    def __getitem__(self, key):
        """get element"""
        return(self._data[key])

    def __repr__(self):
        """return string representation"""
        s = self._data.__repr__()
        s = s + '\t' + str(self.size)
        s = s + '\t' + self.get_all()[::-1].__repr__()
        s = s + '\t' + self.get_partial()[::-1].__repr__()
        return(s)

class RingBufferFull(RingBuffer):
    def append(self, value):
        """append an element when buffer is full"""
        self._data = np.roll(self._data, 1)
        self._data[0] = value

4
+1 für die Verwendung von numpy, aber -1 für die Nichtimplementierung eines Ringpuffers. So wie Sie es implementiert haben, verschieben Sie alle Daten jedes Mal, wenn Sie ein einzelnes Element hinzufügen. Dies kostet O(n)Zeit. Um einen richtigen Umlaufpuffer zu implementieren , sollten Sie sowohl einen Index als auch eine Größenvariable haben und den Fall korrekt behandeln, wenn die Daten das Ende des Puffers "umschließen". Beim Abrufen von Daten müssen Sie möglicherweise zwei Abschnitte am Anfang und Ende des Puffers verketten.
Bas Swinckels

2

Dieser benötigt keine Bibliothek. Es wird eine Liste erstellt und anschließend ein Index erstellt.

Der Footprint ist sehr klein (keine Bibliothek) und läuft mindestens doppelt so schnell wie die Warteschlange. Dies ist in der Tat gut, um gleitende Durchschnitte zu berechnen. Beachten Sie jedoch, dass die Elemente nicht wie oben nach Alter sortiert sind.

class CircularBuffer(object):
    def __init__(self, size):
        """initialization"""
        self.index= 0
        self.size= size
        self._data = []

    def record(self, value):
        """append an element"""
        if len(self._data) == self.size:
            self._data[self.index]= value
        else:
            self._data.append(value)
        self.index= (self.index + 1) % self.size

    def __getitem__(self, key):
        """get element by index like a regular array"""
        return(self._data[key])

    def __repr__(self):
        """return string representation"""
        return self._data.__repr__() + ' (' + str(len(self._data))+' items)'

    def get_all(self):
        """return a list of all the elements"""
        return(self._data)

Um den Durchschnittswert zu erhalten, z.

q= CircularBuffer(1000000);
for i in range(40000):
    q.record(i);
print "capacity=", q.size
print "stored=", len(q.get_all())
print "average=", sum(q.get_all()) / len(q.get_all())

Ergebnisse in:

capacity= 1000000
stored= 40000
average= 19999

real 0m0.024s
user 0m0.020s
sys  0m0.000s

Dies ist ungefähr 1/3 der Zeit des Äquivalents mit Warteschlange.


1
Solltest du __getitem__nicht ein bisschen mächtiger sein : self._data[(key + self._index + 1) % self._size]?
Mateen Ulhaq

Warum sollten Sie um +1 verschieben wollen? Nun ja, siehe Basj Variante unten für die Idee
MoonCactus

1

Ich hatte dieses Problem vor der seriellen Programmierung. Zu der Zeit vor etwas mehr als einem Jahr konnte ich auch keine effizienten Implementierungen finden, so dass ich eine als C-Erweiterung schrieb und sie auch auf pypi unter einer MIT-Lizenz verfügbar ist . Es ist super einfach, verarbeitet nur Puffer mit 8-Bit-Zeichen mit Vorzeichen, hat jedoch eine flexible Länge, sodass Sie Struct oder etwas darüber verwenden können, wenn Sie etwas anderes als Zeichen benötigen. Ich sehe jetzt mit einer Google-Suche, dass es heutzutage jedoch mehrere Optionen gibt, also sollten Sie sich diese auch ansehen.


1

Ihre Antwort ist nicht richtig. Circular Buffer Main haben zwei Prinzipien ( https://en.wikipedia.org/wiki/Circular_buffer )

  1. Das Lenth des Puffers ist gesetzt;
  2. Als Erster rein, als erster raus;
  3. Wenn Sie ein Element hinzufügen oder löschen, sollten die anderen Elemente ihre Position nicht verschieben

Ihr Code unten:

def add_to_buffer( self, num ):
    self.mylist.pop( 0 )
    self.mylist.append( num )

Betrachten wir eine Situation, in der die Liste voll ist, indem Sie Ihren Code verwenden:

self.mylist = [1, 2, 3, 4, 5]

Jetzt fügen wir 6 hinzu, die Liste wird in geändert

self.mylist = [2, 3, 4, 5, 6]

Die Elemente erwarten, dass 1 in der Liste ihre Position geändert hat

Ihr Code ist eine Warteschlange, kein Kreispuffer.

Die Antwort von Basj ist meiner Meinung nach die effizienteste.

Übrigens kann ein Kreispuffer die Leistung der Operation zum Hinzufügen eines Elements verbessern.


1

Von Github:

class CircularBuffer:

    def __init__(self, size):
        """Store buffer in given storage."""
        self.buffer = [None]*size
        self.low = 0
        self.high = 0
        self.size = size
        self.count = 0

    def isEmpty(self):
        """Determines if buffer is empty."""
        return self.count == 0

    def isFull(self):
        """Determines if buffer is full."""
        return self.count == self.size

    def __len__(self):
        """Returns number of elements in buffer."""
        return self.count

    def add(self, value):
        """Adds value to buffer, overwrite as needed."""
        if self.isFull():
            self.low = (self.low+1) % self.size
        else:
            self.count += 1
        self.buffer[self.high] = value
        self.high = (self.high + 1) % self.size

    def remove(self):
        """Removes oldest value from non-empty buffer."""
        if self.count == 0:
            raise Exception ("Circular Buffer is empty");
        value = self.buffer[self.low]
        self.low = (self.low + 1) % self.size
        self.count -= 1
        return value

    def __iter__(self):
        """Return elements in the circular buffer in order using iterator."""
        idx = self.low
        num = self.count
        while num > 0:
            yield self.buffer[idx]
            idx = (idx + 1) % self.size
            num -= 1

    def __repr__(self):
        """String representation of circular buffer."""
        if self.isEmpty():
            return 'cb:[]'

        return 'cb:[' + ','.join(map(str,self)) + ']'

https://github.com/heineman/python-data-structures/blob/master/2.%20Ubiquitous%20Lists/circBuffer.py


0

Die ursprüngliche Frage war: " effizienter " Ringpuffer. Entsprechend dieser geforderten Effizienz scheint die Antwort von aaronasterling definitiv richtig zu sein. Die Verwendung einer in Python programmierten dedizierten Klasse und der Vergleich der Zeitverarbeitung mit collection.deque zeigt eine x5,2-fache Beschleunigung mit deque! Hier ist ein sehr einfacher Code, um dies zu testen:

class cb:
    def __init__(self, size):
        self.b = [0]*size
        self.i = 0
        self.sz = size
    def append(self, v):
        self.b[self.i] = v
        self.i = (self.i + 1) % self.sz

b = cb(1000)
for i in range(10000):
    b.append(i)
# called 200 times, this lasts 1.097 second on my laptop

from collections import deque
b = deque( [], 1000 )
for i in range(10000):
    b.append(i)
# called 200 times, this lasts 0.211 second on my laptop

Um eine Deque in eine Liste umzuwandeln, verwenden Sie einfach:

my_list = [v for v in my_deque]

Sie erhalten dann O (1) zufälligen Zugriff auf die Deque-Elemente. Dies ist natürlich nur dann von Nutzen, wenn Sie nach einmaligem Einstellen viele zufällige Zugriffe auf die Deque vornehmen müssen.


0

Dies wendet dasselbe Prinzip auf einige Puffer an, die die neuesten Textnachrichten enthalten sollen.

import time
import datetime
import sys, getopt

class textbffr(object):
    def __init__(self, size_max):
        #initialization
        self.posn_max = size_max-1
        self._data = [""]*(size_max)
        self.posn = self.posn_max

    def append(self, value):
        #append an element
        if self.posn == self.posn_max:
            self.posn = 0
            self._data[self.posn] = value   
        else:
            self.posn += 1
            self._data[self.posn] = value

    def __getitem__(self, key):
        #return stored element
        if (key + self.posn+1) > self.posn_max:
            return(self._data[key - (self.posn_max-self.posn)])
        else:
            return(self._data[key + self.posn+1])


def print_bffr(bffr,bffer_max): 
    for ind in range(0,bffer_max):
        stored = bffr[ind]
        if stored != "":
            print(stored)
    print ( '\n' )

def make_time_text(time_value):
    return(str(time_value.month).zfill(2) + str(time_value.day).zfill(2)
      + str(time_value.hour).zfill(2) +  str(time_value.minute).zfill(2)
      + str(time_value.second).zfill(2))


def main(argv):
    #Set things up 
    starttime = datetime.datetime.now()
    log_max = 5
    status_max = 7
    log_bffr = textbffr(log_max)
    status_bffr = textbffr(status_max)
    scan_count = 1

    #Main Loop
    # every 10 secounds write a line with the time and the scan count.
    while True: 

        time_text = make_time_text(datetime.datetime.now())
        #create next messages and store in buffers
        status_bffr.append(str(scan_count).zfill(6) + " :  Status is just fine at : " + time_text)
        log_bffr.append(str(scan_count).zfill(6) + " : " + time_text + " : Logging Text ")

        #print whole buffers so far
        print_bffr(log_bffr,log_max)
        print_bffr(status_bffr,status_max)

        time.sleep(2)
        scan_count += 1 

if __name__ == '__main__':
    main(sys.argv[1:])  

0

Sie können diesen zirkulären Puffer basierend auf einem vordefinierten numpy-Array mit Größe auschecken. Die Idee ist, dass Sie einen Puffer erstellen (Speicher für das numpy-Array zuweisen) und ihn später anhängen. Das Einfügen und Abrufen von Daten erfolgt sehr schnell. Ich habe dieses Modul für einen ähnlichen Zweck erstellt, wie Sie es benötigen. In meinem Fall habe ich ein Gerät, das ganzzahlige Daten generiert. Ich lese die Daten und lege sie für zukünftige Analysen und Verarbeitungen in den Umlaufpuffer.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.