go语言扩容方法有哪几种

go语言扩容方法有:1、Slice扩容,在使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容;2、Map扩容。触发Map扩容的条件有二个:1、负载因子大于6.5时,也即平均每个bucket存储的键值对达到6.5个;2、overflow数量大于2^15时,也即overflow数量超过32768时。

go语言扩容方法有哪几种

本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。

Slice扩容

触发

使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容

原理

扩容实际上是重新分配一块更大的内存,将原Slice数据拷贝进新Slice,然后返回新Slice,扩容后再将数据追加进去。

机制

V1.8之前:

扩容容量的选择遵循以下规则:

立即学习“go语言免费学习笔记(深入)”;

如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍;如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍;

// 1.17及以前的版本中// old指切片的旧容量, cap指期望的新容量func growslice(old, cap int) int {    newcap := old    doublecap := newcap + newcap    // 如果期望容量大于旧容量的2倍,则直接使用期望容量作为最终容量    if cap > doublecap {        newcap = cap    } else {        // 如果旧容量小于1024,则直接翻倍        if old < 1024 {            newcap = doublecap        } else {            // 每次增长大约1.25倍            for 0 < newcap && newcap < cap {                newcap += newcap / 4            }            if newcap <= 0 {                newcap = cap            }        }    }    // 这里忽略了对齐操作    return newcap}

登录后复制

V1.8之后:

新扩容容量的选择遵循以下规则:(拥有更平滑的扩容系数)

如果原Slice容量小于256,则新Slice容量将扩大为原来的2倍;如果原Slice容量大于等于256,则新Slice容量将扩大为原来的  新容量 = (原容量+3*256)/4

// 只关心扩容规则的简化版growslicefunc growslice(old, cap int) int {    newcap := old    doublecap := newcap + newcap    if cap > doublecap {        newcap = cap    } else {        const threshold = 256 // 不同点1        if old < threshold {            newcap = doublecap        } else {            for 0 < newcap && newcap < cap {                newcap += (newcap + 3*threshold) / 4 // 不同点2            }            if newcap <= 0 {                newcap = cap            }        }    }    return newcap}

登录后复制

Map扩容

触发扩容的条件有二个:

负载因子 > 6.5时,也即平均每个bucket存储的键值对达到6.5个。增量扩容

overflow数量 > 2^15时,也即overflow数量超过32768时。等量扩容/重排

注意:创建溢出桶不属于扩容机制

增量扩容

当负载因子过大时,新开辟buckets空间,bucket数量为之前的 2 倍新空间被buckets引用,之前的旧空间被oldbuckets引用之后逐渐将 oldbuckets中的数据 搬迁到 新开辟的 buckets空间中去

考虑到如果map存储了数以亿计的key-value,一次性搬迁将会造成比较大的延时,Go采用逐步搬迁策略,即每次访问map时都会触发一次搬迁,每次搬迁2个键值对当oldbuckets中的键值对全部搬迁完毕后,删除oldbuckets。

下图展示了包含一个bucket满载的map(为了描述方便,图中bucket省略了value区域):

go语言扩容方法有哪几种

当前map存储了7个键值对,只有1个bucket。此时负载因子为7 > 6.5。再次插入数据时将会触发扩容操作,扩容之后再将新插入键写入新的bucket。注意,因为负载因子的触发,不是创建溢出桶

当第8个键值对插入时,将会触发扩容扩容后示意图如下:

go语言扩容方法有哪几种

后续对map的访问操作会触发迁移,将oldbuckets中的键值对逐步的搬迁过来。

搬迁完成后的示意图如下:

go语言扩容方法有哪几种

数据搬迁过程中原bucket中的键值对将存在于新bucket的前面,新插入的键值对将存在于新bucket的后面。

等量扩容/重排

所谓等量扩容,实际上并不是扩大容量,buckets数量不变,重新做一遍类似增量扩容的搬迁动作,把松散的键值对重新排列一次,以使bucket的使用率更高,进而保证更快的存取。
在极端场景下,比如不断地增删,而键值对正好集中在一小部分的bucket,这样会造成overflow的bucket数量增多,但负载因子又不高,从而无法执行增量搬迁的情况,如下图所示:

go语言扩容方法有哪几种

上图可见,overflow的bucket中大部分是空的,访问效率会很差。此时进行一次等量扩容,即buckets数量不变,经过重新组织后overflow的bucket数量会减少,即节省了空间又会提高访问效率。

【相关推荐:Go视频教程、编程教学】

以上就是go语言扩容方法有哪几种的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2414939.html

(0)
上一篇 2025年3月3日 00:48:12
下一篇 2025年3月1日 03:07:58

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Go语言怎么判断指定字符是否存在

    判断方法:1、使用index()函数判断,可以在字符串中查找指定字符第一次出现的位置,语法“strings.Index(str,指定字符)”,如果返回“-1”则不存在,否则存在。2、使用ContainsRune()函数判断,可以判断字符是否…

    2025年3月3日
    200
  • Go语言怎么获取函数执行时间

    在Go语言中,可以使用time包中的Since()函数来获取函数执行时间。在函数执行之前设置一个起始时间,并在函数运行结束时获取从起始时间到现在的时间间隔,这个时间间隔就是函数的执行时间;而函数执行时间可以使用time.Since()函数计…

    2025年3月3日
    200
  • go语言怎么将float转string类型

    转换方法:1、使用Sprintf()函数,支持将float32、float64转为string,语法“str := fmt.Sprintf(“%f”, floatVar)”。2、使用FormatFloat()函数,可…

    2025年3月3日
    200
  • LiteIDE是什么

    LiteIDE是一款专为Go语言开发而设计的开源、跨平台、轻量级集成开发环境(IDE),是Go语言的一个开发工具,基于Qt开发(一个跨平台的C++框架),支持Windows、Linux和Mac OS X平台。 本教程操作环境:windows…

    2025年3月3日 编程技术
    200
  • GoClipse是什么

    GoClipse是一款用于go语言开发的Eclipse IDE插件,拥有非常多的特性以及通过GoCode来实现代码补全功能;它是一个非常好的编辑器,拥有完善的代码补全、抽象语法树视图、项目管理和程序调试功能。代码补全一般都是通过内置GoCo…

    2025年3月3日 编程技术
    200
  • go语言中遍历数组的方法有哪些

    遍历数组有两种方法:1、用for循环语句遍历数组,语法“for i :=0;i 本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。 Go 语言 的 数组 的遍历,有两种方式,分别为:通过 for 循环 与 通过 …

    2025年3月3日
    200
  • go语言中build命令怎么用

    在go语言中,“go build”命令主要用于编译代码,可以将Go语言程序代码编译成二进制的可执行文件,但是需要手动运行该二进制文件。“go build”有很多种编译方法,如无参数编译、文件列表编译、指定包编译等,使用这些方法都可以输出可执…

    2025年3月3日
    200
  • go语言怎么删除字符串中的空格

    删除方法:1、使用TrimSpace()函数去除字符串左右两边的空格,语法“strings.TrimSpace(str)”;2、使用Trim()函数去除字符串左右两边的空格,语法“strings.Trim(str, ” &#82…

    2025年3月3日 编程技术
    200
  • go属于哪种语言

    go属于静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言;Go需要使用编译器来编译代码。编译器将源代码编译成二进制(或字节码)格式;在编译代码时,编译器检查错误、优化性能并输出可在不同平台上运行的二进制文件。 本教程操作环境:win…

    2025年3月3日
    200
  • go语言怎么向列表中添加列表

    在go语言中,可以利用PushFrontList()函数和PushBackList()函数来向列表中添加列表。PushFrontList()函数可以在列表头部插入另一个列表,语法“列表变量.PushFrontList(要插入的列表)”;Pu…

    2025年3月3日
    200

发表回复

登录后才能评论