đệm tròn hiệu quả?


109

Tôi muốn tạo một bộ đệm tròn hiệu quả trong python (với mục tiêu lấy giá trị trung bình của các số nguyên trong bộ đệm).

Đây có phải là cách hiệu quả để sử dụng danh sách để thu thập các giá trị không?

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

Điều gì sẽ hiệu quả hơn (và tại sao)?


Đây không phải là một cách hiệu quả để triển khai bộ đệm tròn vì pop (0) là hoạt động O (n) trong danh sách. pop (0) xóa phần tử đầu tiên trong danh sách và tất cả các phần tử phải được chuyển sang bên trái. Thay vào đó hãy sử dụng collection.deque với thuộc tính maxlen. deque có hoạt động O (1) cho append và pop.
Vlad Bezden

Câu trả lời:


205

Tôi sẽ sử dụng collections.dequevới một maxlenarg

>>> 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)

Có một công thức trong tài liệu dequetương tự như những gì bạn muốn. Khẳng định của tôi rằng đó là hiệu quả nhất hoàn toàn dựa vào thực tế là nó được thực hiện trong C bởi một đội ngũ cực kỳ có tay nghề cao, những người có thói quen tạo ra mã hàng đầu.


7
+1 Vâng, đó là cách bao gồm pin đẹp. Hoạt động cho bộ đệm tròn là O (1) và như bạn nói overhead thêm là trong C, vì vậy vẫn nên được khá nhanh
John La Rooy

7
Tôi không thích giải pháp này vì tài liệu không đảm bảo O (1) truy cập ngẫu nhiên khi maxlenđược xác định. O (n) có thể hiểu được khi giá trị dequecó thể phát triển đến vô cùng, nhưng nếu maxlenđược cho trước, lập chỉ mục một phần tử phải là thời gian không đổi.
lvella

1
Tôi đoán rằng nó được triển khai dưới dạng danh sách liên kết chứ không phải một mảng.
e-thoả mãn

1
Có vẻ đúng, nếu thời gian trong câu trả lời của tôi dưới đây là chính xác.
djvg

13

việc xuất hiện từ đầu danh sách khiến toàn bộ danh sách được sao chép, do đó không hiệu quả

Thay vào đó, bạn nên sử dụng một danh sách / mảng có kích thước cố định và một chỉ mục di chuyển qua bộ đệm khi bạn thêm / xóa các mục


4
Đồng ý. Bất kể nó có thể trông thanh lịch hay không trang nhã hay bất kỳ ngôn ngữ nào được sử dụng. Trong thực tế, bạn càng ít bận tâm đến bộ thu gom rác (hoặc trình quản lý heap hoặc cơ chế phân trang / ánh xạ hoặc bất cứ điều gì làm phép bộ nhớ thực tế) thì càng tốt.

@RocketSurgeon Nó không phải là phép thuật, nó chỉ là một mảng có phần tử đầu tiên bị xóa. Vì vậy, đối với một mảng có kích thước n, điều này có nghĩa là n-1 hoạt động sao chép. Không có người thu gom rác hoặc thiết bị tương tự được tham gia ở đây.
Christian

3
Tôi đồng ý. Làm như vậy cũng dễ dàng hơn nhiều so với một số người nghĩ. Chỉ cần sử dụng bộ đếm ngày càng tăng và sử dụng toán tử modulo (% arraylen) khi truy cập mục.
Andre Blum

idem, bạn có thể kiểm tra bài viết của tôi ở trên, đó là cách tôi đã làm nó
MoonCactus

10

Dựa trên câu trả lời của MoonCactus , đây là một circularlistlớp học. Sự khác biệt với phiên bản của anh ấy là ở đây c[0]sẽ luôn đưa ra phần tử nối cũ nhất, phần tử nối c[-1]mới nhất, c[-2]áp chót ... Điều này tự nhiên hơn cho các ứng dụng.

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

Lớp học:

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)'

[Đã chỉnh sửa]: Đã thêm datatham số tùy chọn để cho phép khởi tạo từ danh sách hiện có, ví dụ:

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)

Bổ sung tốt. Danh sách Python đã cho phép các chỉ số âm, nhưng (-1), ví dụ: sẽ không trả về giá trị mong đợi khi bộ đệm tròn đầy, vì phần bổ sung "cuối cùng" vào danh sách kết thúc trong danh sách.
MoonCactus

1
Nó hoạt động @MoonCactus, hãy xem 6 ví dụ tôi đã đưa ra ở đầu câu trả lời; trong những cái cuối cùng, bạn có thể thấy c[-1]luôn là phần tử phù hợp. __getitem__làm đúng.
Basj

Ồ vâng, ý tôi là tôi đã thất bại, không phải của bạn, xin lỗi: DI sẽ làm cho nhận xét của tôi rõ ràng hơn! - Ồ, tôi không thể, nhận xét quá cũ.
MoonCactus

giải pháp đơn giản tốt đẹp. tôi đã thêm một đối số tùy chọn để cho phép khởi tạo danh sách từ dữ liệu hiện có, theo cách đó, nó mang tính chất trăn trở hơn.
Orwellophile,

9

Deque của Python chậm. Bạn cũng có thể sử dụng numpy.roll để thay thế Làm cách nào để xoay các số trong một mảng có hình dạng (n,) hoặc (n, 1)?

Trong điểm chuẩn này, deque là 448ms. Numpy.roll là 29ms http://scimusing.wordpress.com/2013/10/25/ring-buffers-in-pythonnumpy/


1
Nhưng numpy.rolltrả về một bản sao của mảng, phải không?
djvg

3
Câu trả lời này rất dễ gây hiểu lầm - deque của Python có vẻ khá nhanh, nhưng việc chuyển đổi từ và sang mảng numpy làm chậm nó đáng kể trong các điểm chuẩn mà bạn liên kết đến.
xitrium

7

ok với việc sử dụng deque class, nhưng đối với các truy vấn lại của câu hỏi (trung bình) thì đây là giải pháp của tôi:

>>> 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

Tôi nhận được TypeError: 'numpy.float64' object is not callablekhi cố gắng gọi averagephương pháp
scls

Vâng ... trên thực tế, tôi đoán rằng deque sử dụng các mảng numpy bên trong (sau khi loại bỏ @property, nó hoạt động tốt)
scls

17
Tôi đảm bảo rằng deque không sử dụng mảng numpy bên trong. collectionslà một phần của thư viện tiêu chuẩn, numpykhông. Sự phụ thuộc vào thư viện của bên thứ ba sẽ tạo nên một thư viện tiêu chuẩn khủng khiếp.

6

Mặc dù đã có rất nhiều câu trả lời tuyệt vời ở đây, nhưng tôi không thể tìm thấy bất kỳ so sánh trực tiếp nào về thời gian cho các tùy chọn được đề cập. Do đó, hãy tìm nỗ lực khiêm tốn của tôi trong một so sánh dưới đây.

Chỉ dành cho mục đích thử nghiệm, lớp có thể chuyển đổi giữa listbộ đệm collections.dequedựa trên cơ sở, bộ đệm dựa trên cơ sở và Numpy.rollbộ đệm dựa trên cơ sở.

Lưu ý rằng updatephương pháp chỉ thêm một giá trị tại một thời điểm, để giữ cho nó đơn giản.

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)

Trên hệ thống của tôi, kết quả là:

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

Làm thế nào về giải pháp từ Python Cookbook , bao gồm phân loại lại cá thể bộ đệm vòng khi nó đầy?

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())

Lựa chọn thiết kế đáng chú ý trong quá trình triển khai là, vì các đối tượng này trải qua quá trình chuyển đổi trạng thái không thể đảo ngược tại một số thời điểm trong vòng đời của chúng — từ bộ đệm không đầy đủ sang bộ đệm đầy đủ (và hành vi thay đổi tại điểm đó) - Tôi đã mô hình hóa điều đó bằng cách thay đổi self.__class__. Điều này hoạt động ngay cả trong Python 2.2, miễn là cả hai lớp có cùng vị trí (ví dụ: nó hoạt động tốt cho hai lớp cổ điển, chẳng hạn như RingBuffer và __Fulltrong công thức này).

Thay đổi lớp của một thể hiện có thể lạ trong nhiều ngôn ngữ, nhưng nó là một cách thay thế Pythonic cho các cách khác để biểu thị những thay đổi trạng thái không thường xuyên, lớn, không thể đảo ngược và rời rạc ảnh hưởng lớn đến hành vi, như trong công thức này. Điều tốt là Python hỗ trợ nó cho tất cả các loại lớp.

Tín dụng: Sébastien Keim


Tôi đã thực hiện một số bài kiểm tra tốc độ của điều này so với deque. Điều này chậm hơn khoảng 7 lần so với deque.
PolyMesh

@PolyMesh tuyệt vời, bạn nên cho tác giả biết!
d8aninja

1
mục đích của điều đó là gì? Đó là một tài liệu đã xuất bản cũ. Ý kiến ​​của tôi là cho người khác biết rằng câu trả lời này đã lỗi thời và sử dụng deque để thay thế.
PolyMesh

@PolyMesh có lẽ vẫn còn chậm hơn khi anh ấy xuất bản nó; hướng dẫn liên hệ với tác giả có trong phần giới thiệu của cuốn sách. Tôi chỉ liên quan một, có thể thay thế. Ngoài ra, "Giá như tốc độ là chỉ số tốt nhất; than ôi, nó có thể chỉ là một chỉ số tốt."
d8aninja

3

Bạn cũng có thể xem công thức Python khá cũ này .

Đây là phiên bản của riêng tôi với mảng NumPy:

#!/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 để sử dụng numpy, nhưng -1 để không triển khai bộ đệm tròn. Theo cách bạn triển khai, bạn đang thay đổi tất cả dữ liệu mỗi khi bạn thêm một phần tử, điều này tốn O(n)thời gian. Để triển khai một bộ đệm tròn thích hợp , bạn nên có cả chỉ mục và biến kích thước, và bạn cần xử lý chính xác trường hợp khi dữ liệu 'quấn quanh' phần cuối của bộ đệm. Khi truy xuất dữ liệu, bạn có thể phải nối hai phần ở đầu và cuối của bộ đệm.
Bas Swinckels

2

Cái này không yêu cầu bất kỳ thư viện nào. Nó phát triển một danh sách và sau đó xoay vòng theo chỉ mục.

Dấu chân rất nhỏ (không có thư viện), và nó chạy nhanh gấp đôi so với dequeue ít nhất. Điều này thực sự tốt để tính toán đường trung bình động, nhưng lưu ý rằng các mục không được sắp xếp theo độ tuổi như trên.

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)

Để nhận giá trị trung bình, ví dụ:

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())

Kết quả trong:

capacity= 1000000
stored= 40000
average= 19999

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

Đây là khoảng 1/3 thời gian tương đương với dequeue.


1
Bạn không nên __getitem__mạnh mẽ hơn một chút self._data[(key + self._index + 1) % self._size]sao:?
Mateen Ulhaq

Tại sao bạn muốn thay đổi bằng +1? Bây giờ, có, hãy xem biến thể Basj bên dưới để biết ý tưởng
MoonCactus

1

Tôi đã gặp sự cố này trước khi thực hiện lập trình nối tiếp. Vào thời điểm chỉ hơn một năm trước, tôi cũng không thể tìm thấy bất kỳ triển khai hiệu quả nào, vì vậy tôi đã viết một phần mở rộng dưới dạng C và nó cũng có sẵn trên pypi theo giấy phép của MIT. Nó siêu cơ bản, chỉ xử lý bộ đệm của các ký tự có ký 8-bit, nhưng có độ dài linh hoạt, vì vậy bạn có thể sử dụng Struct hoặc thứ gì đó trên đó nếu bạn cần thứ gì đó khác ngoài ký tự. Tôi thấy bây giờ với một tìm kiếm trên google, mặc dù vậy, có một số tùy chọn ngày nay, vì vậy bạn cũng có thể muốn xem những tùy chọn đó.


1

Bạn trả lời là không đúng. Bộ đệm tròn chính có hai phần tử chính (https://en.wikipedia.org/wiki/Circular_buffer )

  1. Phần mười của bộ đệm được thiết lập;
  2. Đến trước về trước;
  3. Khi bạn thêm hoặc xóa một mục, các mục khác sẽ không di chuyển vị trí của chúng

mã của bạn bên dưới:

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

Hãy xem xét một tình huống mà danh sách đã đầy bằng cách sử dụng mã của bạn:

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

bây giờ chúng tôi thêm 6, danh sách được thay đổi thành

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

các mục mong đợi 1 trong danh sách đã thay đổi vị trí của chúng

mã của bạn là một hàng đợi, không phải một bộ đệm vòng tròn.

Câu trả lời của Basj, tôi nghĩ là câu trả lời hiệu quả nhất.

Nhân tiện, bộ đệm vòng tròn có thể thúc đẩy hiệu suất của hoạt động thêm một mục.


1

Từ 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

Câu hỏi ban đầu là: bộ đệm tròn " hiệu quả ". Theo hiệu quả này được yêu cầu, câu trả lời từ aaronasterling dường như hoàn toàn đúng. Sử dụng một lớp chuyên dụng được lập trình bằng Python và so sánh thời gian xử lý với collection.deque cho thấy khả năng tăng tốc x5,2 lần với deque! Đây là mã rất đơn giản để kiểm tra điều này:

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

Để chuyển đổi một deque thành một danh sách, chỉ cần sử dụng:

my_list = [v for v in my_deque]

Sau đó, bạn sẽ nhận được O (1) quyền truy cập ngẫu nhiên vào các mục deque. Tất nhiên, điều này chỉ có giá trị nếu bạn cần thực hiện nhiều lần truy cập ngẫu nhiên vào deque sau khi đã đặt nó một lần.


0

Điều này đang áp dụng cùng một nguyên tắc chính cho một số bộ đệm nhằm lưu giữ các tin nhắn văn bản gần đây nhất.

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

Bạn có thể kiểm tra bộ đệm tròn này dựa trên một mảng numpy có kích thước được xác định trước. Ý tưởng là bạn tạo một bộ đệm (cấp phát bộ nhớ cho mảng numpy) và sau đó thêm vào đó. Việc chèn và truy xuất dữ liệu rất nhanh chóng. Tôi đã tạo mô-đun này cho một mục đích tương tự như bạn cần. Trong trường hợp của tôi, tôi có một thiết bị tạo dữ liệu số nguyên. Tôi đọc dữ liệu và đặt nó vào bộ đệm tròn để phân tích và xử lý trong tương lai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.