go内存队列的实现 -- list VS slice

【go内存队列的实现 -- list VS slice】golang中没有队列这种数据结构,通常需要自己实现,常见的可以通过list或slice实现。
go队列的实现方式 list是"container/list"中的数据结构,用双向链表实现,可以用来做队列:

//入队 func (l *List) PushBack(v interface{}) *Element//出队:先Front()取得头,然后Remove()删除 func (l *List) Front() *Element func (l *List) Remove(e *Element) interface{}

slice实现队列的方式:
var s []obj s = append(s, obj)//入队 s = s[1:]//出队

benchmark测试比较 benchmark测试代码: 队列中存入object对象
type EventMsg struct { Idstring Msg string }func BenchmarkQueue_ListObject(b *testing.B) { var l = list.New() for i := 0; i < b.N; i++ { l.PushBack(EventMsg{ Id:strconv.Itoa(i), Msg: "1:abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz", }) l.PushBack(EventMsg{ Id:strconv.Itoa(i), Msg: "1:opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn", }) l.Remove(l.Front()) } }func BenchmarkQueue_SliceObject(b *testing.B) { var q []EventMsg for i := 0; i < b.N; i++ { q = append(q, EventMsg{ Id:strconv.Itoa(i), Msg: "1:abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz", }) q = append(q, EventMsg{ Id:strconv.Itoa(i), Msg: "1:opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn", }) q = q[1:] } }

benchmark测试代码:队列中存入Object指针对象
func BenchmarkQueue_ListObjPtr(b *testing.B) { var l = list.New() for i := 0; i < b.N; i++ { l.PushBack(&EventMsg{ Id:strconv.Itoa(i), Msg: "1:abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz", }) l.PushBack(&EventMsg{ Id:strconv.Itoa(i), Msg: "1:opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn", }) l.Remove(l.Front()) } } func BenchmarkQueue_SliceObjPtr(b *testing.B) { var q []*EventMsg for i := 0; i < b.N; i++ { q = append(q, &EventMsg{ Id:strconv.Itoa(i), Msg: "1:abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz", }) q = append(q, &EventMsg{ Id:strconv.Itoa(i), Msg: "1:opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn-opqrstuvwxyzabcdefghijklmn", }) q = q[1:] } }

benchmark测试结果
# go test -bench=BenchmarkQueue -count=1 -benchmem -cpu 4 BenchmarkQueue_ListObject-410000001423 ns/op175 B/op5 allocs/op BenchmarkQueue_ListObjPtr-410000001124 ns/op175 B/op5 allocs/op BenchmarkQueue_SliceObject-410000001574 ns/op357 B/op1 allocs/op BenchmarkQueue_SliceObjPtr-41831449662.7 ns/op161 B/op3 allocs/op PASS okgithub.com/go_list/bench_test6.144s

结论:
  • 不管用list还是slice,队列中存储对象指针的性能,要好于直接存储对象;
  • slice实现的队列,存储指针对象时性能最好;
  • list实现的队列,不管是存储对象还是指针对象,其性能差异不是太大;
Open-falcon的队列实现 open-falcon使用list和mutex实现了一个协程安全的内存队列。
实现代码:https://github.com/toolkits/c...
type SafeList struct { sync.RWMutex L *list.List } func NewSafeList() *SafeList { return &SafeList{L: list.New()} } //入队 func (this *SafeList) PushFront(v interface{}) *list.Element { this.Lock() e := this.L.PushFront(v) this.Unlock() return e } //出队 func (this *SafeList) PopBack() interface{} { this.Lock() if elem := this.L.Back(); elem != nil { item := this.L.Remove(elem) this.Unlock() return item } this.Unlock() return nil }

参考: 1.https://blog.wolfogre.com/pos...

    推荐阅读