go内存队列list VS slice实现方式对比分析

 更新时间:2023年08月20日 14:24:47   作者:a朋  
这篇文章主要为大家介绍了go内存队列list VS slice实现方式对比分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

go队列的实现方式

golang中没有队列这种数据结构,通常需要自己实现,常见的可以通过list或slice实现。

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
}

参考:https://www.jb51.net/jiaoben/2957122cc.htm

以上就是go内存队列list VS slice实现方式对比分析的详细内容,更多关于go内存队列list slice的资料请关注脚本之家其它相关文章!

相关文章

  • Go扩展原语之SingleFlight的用法详解

    Go扩展原语之SingleFlight的用法详解

    Go语言扩展包同步原语singleflight.Group能够再一个服务中抑制对下游的多次重复请求,它能够限制对同一个键值对的多次重复请求,减少对下游的瞬时流量,接下来小编就给大家讲讲Go SingleFlight的具体用法,需要的朋友可以参考下
    2023-07-07
  • Go语言interface详解

    Go语言interface详解

    这篇文章主要介绍了Go语言interface详解,本文讲解了什么是interface、interface类型、interface值、空interface、interface函数参数等内容,需要的朋友可以参考下
    2014-10-10
  • 浅析Go中关于零值和空值判断的问题

    浅析Go中关于零值和空值判断的问题

    这篇文章主要是对零值和空值判断现状进行简单的梳理和分享,文中的示例代码讲解详细,对我们深入了解go语言有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-08-08
  • Go语言利用正则表达式处理多行文本

    Go语言利用正则表达式处理多行文本

    在 Go 语言中处理多行文本的正则表达式时,换行符常常会导致意外的匹配结果,本文为大家整理了一些解决方法,有需要的小伙伴可以参考一下
    2024-11-11
  • Go语言基于HTTP的内存缓存服务的实现

    Go语言基于HTTP的内存缓存服务的实现

    这篇文章主要介绍了Go语言基于HTTP的内存缓存服务,本程序采用REST接口,支持设置(Set)、获取(Get)和删除(Del)这3个基本操作,同时还支持对缓存服务状态进行查询,需要的朋友可以参考下
    2022-08-08
  • 详解golang避免循环import问题(“import cycle not allowed”)

    详解golang避免循环import问题(“import cycle not allowed”)

    这篇文章主要给大家介绍了关于golang中不允许循环import问题("import cycle not allowed")的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-08-08
  • Go项目在GoLand中导入依赖标红问题的解决方案

    Go项目在GoLand中导入依赖标红问题的解决方案

    这篇文章主要介绍了Go项目在GoLand中导入依赖标红问题的解决方案,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-06-06
  • C语言的10大基础算法

    C语言的10大基础算法

    算法是一个程序和软件的灵魂,作为一名优秀的程序员,只有对一些基础的算法有着全面的掌握,才会在设计程序和编写代码的过程中显得得心应手。这篇文章主要介绍了C语言的10大基础算法,需要的朋友可以参考下
    2019-09-09
  • golang读取yaml配置文件的示例代码

    golang读取yaml配置文件的示例代码

    在项目开发中,经常需要把一些配置文件常量提取到统一配置文件进行维护,go项目在开发中常常把需要维护的常量或者配置提取到yaml文件,所以本文主要来为大家介绍一下golang如何读取yaml配置文件吧
    2023-11-11
  • Golang在Window环境使用Imagick7的过程

    Golang在Window环境使用Imagick7的过程

    这篇文章主要介绍了Golang在Window环境使用Imagick7的过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11

最新评论