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实现的队列,不管是存储对象还是指针对象,其性能差异不是太大;
实现代码: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...
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量