Ringbuffer环形队列
55
2023-06-20
RingBuffer
环形缓冲队列,在系统中是非常常见的数据结构,许多场景都是用到了它,例如大名鼎鼎的Linux io_uring,它通过在共享内存中使用环形队列,避免了锁与内核切换的开销,大大提高性能。再比如Golang语言中的channel,在有缓冲的情况下,其内部实现也是通过环形队列的。不过它并非无锁,因为在channel的场景中,必定会面临多个生产者和多个消费者的情况,必须保证线程安全。
简易实现
package ringbuffer
type RingBuffer[T any] struct {
size uint32
buffer []T
head uint32
tail uint32
}
func NewRingBuffer[T any](size uint32) *RingBuffer[T] {
buffer := &RingBuffer[T]{
size: size + 1,
buffer: make([]T, size+1),
head: 0,
tail: 0,
}
return buffer
}
func (r *RingBuffer[T]) Empty() bool {
return r.head == r.tail
}
func (r *RingBuffer[T]) Full() bool {
return r.head == (r.tail+1)%r.size
}
func (r *RingBuffer[T]) Get() (t T, exist bool) {
if r.Empty() {
return
}
t = r.buffer[r.head]
r.head = (r.head + 1) % r.size
return t, true
}
func (r *RingBuffer[T]) Put(t T) (ok bool) {
if r.Full() {
return false
}
r.buffer[r.tail] = t
r.tail = (r.tail + 1) % r.size
return true
}
单元测试
package ringbuffer
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestPut(t *testing.T) {
buffer := NewRingBuffer[string](3)
cases := []struct {
val string
ok bool
}{
{val: "one", ok: true},
{val: "two", ok: true},
{val: "three", ok: true},
{val: "four", ok: false},
}
for _, ca := range cases {
ok := buffer.Put(ca.val)
if ok != ca.ok {
t.Errorf("want %v but got put: %v", ca.ok, ok)
}
}
}
func TestGet(t *testing.T) {
buffer := NewRingBuffer[string](3)
buffer.Put("one")
buffer.Put("two")
val, ok := buffer.Get()
require.True(t, ok)
require.Equal(t, val, "one")
val, ok = buffer.Get()
require.True(t, ok)
require.Equal(t, val, "two")
_, ok = buffer.Get()
require.False(t, ok)
}
- 0
- 0
-
分享