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 {
    Id  string
    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-4      1000000              1423 ns/op             175 B/op          5 allocs/op
BenchmarkQueue_ListObjPtr-4      1000000              1124 ns/op             175 B/op          5 allocs/op
BenchmarkQueue_SliceObject-4     1000000              1574 ns/op             357 B/op          1 allocs/op
BenchmarkQueue_SliceObjPtr-4     1831449               662.7 ns/op           161 B/op          3 allocs/op
PASS
ok      github.com/go_list/bench_test       6.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...

38 声望
21 粉丝
0 条评论
推荐阅读
cadvisor采集docker容器的DiskUsage指标--源码分析
一. DiskUsage指标cadvisor采集的docker容器的DiskUsage指标,包含:container_fs_inodes_freecontainer_fs_inodes_totalcontainer_fs_limit_bytescontainer_fs_usage_bytes {代码...} 二. 采集的过程docker容器...

a朋阅读 507

「刷起来」Go必看的进阶面试题详解
逃逸分析是Go语言中的一项重要优化技术,可以帮助程序减少内存分配和垃圾回收的开销,从而提高程序的性能。下面是一道涉及逃逸分析的面试题及其详解。

王中阳Go4阅读 1.9k评论 1

封面图
初学后端,如何做好表结构设计?
这篇文章介绍了设计数据库表结构应该考虑的4个方面,还有优雅设计的6个原则,举了一个例子分享了我的设计思路,为了提高性能我们也要从多方面考虑缓存问题。

王中阳Go4阅读 1.7k评论 2

封面图
滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许4阅读 2.3k

又一款眼前一亮的Linux终端工具!
今天给大家介绍一款最近发现的功能十分强大,颜值非常高的一款终端工具。这个神器我是在其他公众号文章上看到的,但他们都没把它的强大之处介绍明白,所以我自己体验一波后,再向大家分享自己的体验。

良许5阅读 1.8k

一分钟搞明白!快速掌握 Go WebAssembly
最近因为各种奇怪的原因,更多的接触到了 WebAssembly。虽然之前很多博客也翻过写过各种文章,但总感觉欠些味道。于是今天梳理了一版,和大家一起展开学习。

煎鱼4阅读 2.1k

面试官:请说一下如何优化结构体的性能?
使用内存对齐机制优化结构体性能,妙啊!前言之前分享过2篇结构体文章:10秒改struct性能直接提升15%,产品姐姐都夸我好棒 和 Go语言空结构体这3种妙用,你知道吗? 得到了大家的好评。这篇继续分享进阶内容:结...

王中阳Go4阅读 3.8k评论 2

封面图
38 声望
21 粉丝
宣传栏