go语言扩容方法有:1、Slice扩容,在使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容;2、Map扩容。触发Map扩容的条件有二个:1、负载因子大于6.5时,也即平均每个bucket存储的键值对达到6.5个;2、overflow数量大于2^15时,也即overflow数量超过32768时。
本教程操作环境:windows7系统、GO 1.18版本、Dell G3电脑。
Slice扩容
触发
使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容
原理
扩容实际上是重新分配一块更大的内存,将原Slice数据拷贝进新Slice,然后返回新Slice,扩容后再将数据追加进去。
机制
V1.8之前:
扩容容量的选择遵循以下规则:
- 如果原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
// 只关心扩容规则的简化版growslice func 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区域):
当前map存储了7个键值对,只有1个bucket。此时负载因子为7 > 6.5。再次插入数据时将会触发扩容操作,扩容之后再将新插入键写入新的bucket。注意,因为负载因子的触发,不是创建溢出桶
当第8个键值对插入时,将会触发扩容,扩容后示意图如下:
后续对map的访问操作会触发迁移,将oldbuckets中的键值对逐步的搬迁过来。
搬迁完成后的示意图如下:
数据搬迁过程中原bucket中的键值对将存在于新bucket的前面,新插入的键值对将存在于新bucket的后面。
等量扩容/重排
所谓等量扩容,实际上并不是扩大容量,buckets数量不变,重新做一遍类似增量扩容的搬迁动作,把松散的键值对重新排列一次,以使bucket的使用率更高,进而保证更快的存取。
在极端场景下,比如不断地增删,而键值对正好集中在一小部分的bucket,这样会造成overflow的bucket数量增多,但负载因子又不高,从而无法执行增量搬迁的情况,如下图所示:
上图可见,overflow的bucket中大部分是空的,访问效率会很差。此时进行一次等量扩容,即buckets数量不变,经过重新组织后overflow的bucket数量会减少,即节省了空间又会提高访问效率。
以上是go语言扩容方法有哪几种的详细内容。更多信息请关注PHP中文网其他相关文章!

Golangisidealforbuildingscalablesystemsduetoitsefficiencyandconcurrency,whilePythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.Golang'sdesignencouragesclean,readablecodeanditsgoroutinesenableefficientconcurrentoperations,t

Golang在并发性上优于C ,而C 在原始速度上优于Golang。1)Golang通过goroutine和channel实现高效并发,适合处理大量并发任务。2)C 通过编译器优化和标准库,提供接近硬件的高性能,适合需要极致优化的应用。

选择Golang的原因包括:1)高并发性能,2)静态类型系统,3)垃圾回收机制,4)丰富的标准库和生态系统,这些特性使其成为开发高效、可靠软件的理想选择。

Golang适合快速开发和并发场景,C 适用于需要极致性能和低级控制的场景。1)Golang通过垃圾回收和并发机制提升性能,适合高并发Web服务开发。2)C 通过手动内存管理和编译器优化达到极致性能,适用于嵌入式系统开发。

Golang在编译时间和并发处理上表现更好,而C 在运行速度和内存管理上更具优势。1.Golang编译速度快,适合快速开发。2.C 运行速度快,适合性能关键应用。3.Golang并发处理简单高效,适用于并发编程。4.C 手动内存管理提供更高性能,但增加开发复杂度。

Golang在Web服务和系统编程中的应用主要体现在其简洁、高效和并发性上。1)在Web服务中,Golang通过强大的HTTP库和并发处理能力,支持创建高性能的Web应用和API。2)在系统编程中,Golang利用接近硬件的特性和对C语言的兼容性,适用于操作系统开发和嵌入式系统。

Golang和C 在性能对比中各有优劣:1.Golang适合高并发和快速开发,但垃圾回收可能影响性能;2.C 提供更高性能和硬件控制,但开发复杂度高。选择时需综合考虑项目需求和团队技能。

Golang适合高性能和并发编程场景,Python适合快速开发和数据处理。 1.Golang强调简洁和高效,适用于后端服务和微服务。 2.Python以简洁语法和丰富库着称,适用于数据科学和机器学习。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

Dreamweaver CS6
视觉化网页开发工具

WebStorm Mac版
好用的JavaScript开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。