c ringbuffer 源码_Python Ring Buffer的实现

本文探讨了RingBuffer的概念及其在Python中的实现,包括使用collections.deque和自定义类的方法。通过示例展示了不同实现的性能和特点,并提及了一个C语言实现的pyringbuf库。
摘要由CSDN通过智能技术生成

RingBuffer,或者说Circular Buffer,是一个长度固定的缓冲区,当从一端插入元素超过指定的最大长度时,缓冲区另一端的元素会溢出。当用户仅对近期一定长度的历史记录感兴趣时,这种数据结构就特别有用。

* 缓冲区的长度固定

* 先进先出

* 当往缓冲区中增加或者删除元素时,其它元素的位置保持不变。

本文介绍了三种实现方法及各自的特点。

# collections.dequeue实现

RingBuffer的一个直观实现是使用Pyhton collections的dequeue(发音deck):

```Python

import collections

import time

d = collections.deque(maxlen=1000)

tm1 = time.time()

for i in range(int(1e6)):

d.append(i)

print(list(d)[:10])

d.clear()

tm2 = time.time()

print("{:.2f}seconds".format(tm2 - tm1))

执行结果如下:

[999000, 999001, 999002, 999003, 999004, 999005, 999006, 999007, 999008, 999009]

0.20seconds

支持的操作有pop, append;以及从左端操作的popleft, appendleft。但没有缓冲区需要的read操作。缓冲区read操作包括两个动作,一是从缓冲区中读取数据;二是在读取后清除掉数据。我们可以通过list(d:dequeue)和clear的组合来实现这一功能。

# 一个有趣的自定义实现

David Ascher在[这篇文章](#Implementing a Ring Buffer [Book])里给出了一个自定义的实现:

```python

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

ret = self.data[self.cur:]+self.data[:self.cur]

self.data.clear()

return ret

def append(self,x):

"""append an element at the end of the buffer"""

self.data.append(x)

if len(self.data) == self.max: #line 21

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

x = RingBuffer(1000)

import time

tm1 = time.time()

for i in range(int(1e6)):

x.append(i)

print(x.get()[:10])

tm2 = time.time()

print("{:.2f}seconds".format(tm2 - tm1))

执行结果如下:

[999000, 999001, 999002, 999003, 999004, 999005, 999006, 999007, 999008, 999009]

0.64seconds

这个实现的特点是,使用了数组,而不是双端队列来作为基础存储数据结构。当然由于Ring Buffer的访问特性,我们也基本上只对队头、队尾元素进行操作,所以无论是使用数组还是双端队列,操作复杂度都是O(1)。

另一个值得一提的点是,它使用了动态改变对象_class_实现的方式,避免了不必要的判断语句操作,即在创建之初,缓冲区未满时,每插入一个元素,都要在第19行处进行一次判断;而一旦缓冲区被充满后,RingBuffer对象升级为__Full类,从而行为也从此改变--今后再向缓冲区添加新的元素时,不再进行条件语句判断。

尽管代码做了足够的优化,python内建dequeue的实现性能更高一些。

# 使用C语言的实现-pyringbuf

[sirlark](#sirlark)用C语言实现了一个开源的[RingBuffer](#pyringbuf 0.1b2 : Python Package Index),可以通过pip来安装使用。

pip install pyringbuf

这个模块提供了push, pop, write, read等函数,使用示例如下:

>>> from ringbuf import RingBuffer

>>> R = RingBuffer(5) #choose your buffer size

>>> R.push("a") #push a single character into the buffer

>>> R.pop() #pop a single character

'a'

>>> R.write("bcdef") #fill buffer with many characters at once

>>> R.read(4) #read many characters at once

'bcde'

>>> R.read(1)

'f'

>>> R.read(1) #returns an empty string if the buffer is empty

这个模块以c语言源码提供,使用前需要编译。

Ring Buffer(环形缓冲区)是一种特殊的缓冲区结构,数据的写入端总是追加到缓冲区的尾部,而读取端则从缓冲区头部开始。当一个新元素写入时,如果已满,则会替换掉最早进入缓冲区的数据,形成循环效果。下面是C语言中一个简单的环形缓冲区实现: ```c #include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 10 // 缓冲区大小 typedef struct { int data[BUFFER_SIZE]; int head; // 当前写入位置 int tail; // 当前读取位置 } RingBuffer; // 初始化环形缓冲区 RingBuffer* ring_buffer_init() { RingBuffer* rb = malloc(sizeof(RingBuffer)); if (rb == NULL) { perror("Memory allocation failed"); exit(EXIT_FAILURE); } rb->head = 0; rb->tail = 0; return rb; } // 写入数据到环形缓冲区 void ring_buffer_write(RingBuffer* rb, int value) { rb->data[rb->head] = value; rb->head = (rb->head + 1) % BUFFER_SIZE; } // 读取环形缓冲区数据 int ring_buffer_read(RingBuffer* rb) { if (rb->head == rb->tail) { // 空缓冲区 return -1; } else { rb->tail = (rb->tail + 1) % BUFFER_SIZE; // 移动读指针 return rb->data[rb->tail]; } } // 检查环形缓冲区是否为空 int ring_buffer_empty(const RingBuffer* rb) { return rb->head == rb->tail; } // 清空环形缓冲区 void ring_buffer_clear(RingBuffer* rb) { rb->head = 0; rb->tail = 0; } // 释放环形缓冲区内存 void ring_buffer_destroy(RingBuffer* rb) { free(rb); } int main() { RingBuffer* rb = ring_buffer_init(); // 使用环形缓冲区... ring_buffer_write(rb, 1); ring_buffer_write(rb, 2); printf("%d\n", ring_buffer_read(rb)); // 输出 1 ring_buffer_clear(rb); // 结束后记得释放资源 ring_buffer_destroy(rb); return 0; } ``` 在这个例子中,`ring_buffer_write()`负责向缓冲区添加数据,`ring_buffer_read()`从缓冲区取出数据,`ring_buffer_empty()`检查是否有可用的数据,`ring_buffer_clear()`清空缓冲区内容,`ring_buffer_destroy()`释放内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值