go语言中slice,map,channl底层原理
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《go语言中slice,map,channl底层原理》,聊聊map、原理、底层、goslice、channl,我们一起来看看吧!
0. 前序
slice,map,channl是我们Go语言中最最常用的几个数据结构,对于这些做到知根知底,对于我们建立知识体系以及优化代码都有着很重要的意义,所以本文,我们深入这三个数据结构的底层,剖析其设计思想。
1. slice
1.1 slice的创建
slice的创建主要有两种方式,第一种方式是直接创建
var sli []int sli = make([]int, len, cap) // cap可以省略 //或者 sli := make([]int, len, cap) // cap可以省略
另一种方式是借助array创建:
arr := []int{1,2,3,4,5}
sli := arr[sta:end:cap] // :cap可以省略,以这种方式创建的sli,其cap为sta到arr的最后一位
1.2 数据结构
slice底层数据结构如下:
type {
array unsafe.Pointer // 指针
len int // 现有长度
cap int // 容量
}
在Go语言中,所有的参数传递都是值传递,slice也是如此,不过由于其底层的指针,在其传递到另一个函数后,仍能对其地址对应位置的值做修改,然而,当发生扩容操作时,由于会重新分配地址,就会导致问题的发生,下面我们就来介绍slice的扩容机制。
1.3 扩容机制
在进行append()并且cap不够用的时候,会触发扩容操作(copy()操作不会触发扩容)。
容量的确定:
- 如果期望容量大于当前容量的两倍就会使用期望容量;
- 如果当前切片的长度小于 1024 就会将容量翻倍;
- 如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;
上面所说的是一个容量的初步确定步骤,当数据类型size为1字节,8字节,或者2的倍数时,会根据内存大小进行向上取整,进行内存对齐,之后返回新的扩容大小。
内存对齐的一个重要原因是因为Go进行内存分配时是类似于伙伴系统的固定的内存块,对齐这个内存可以最大化的人利用分配到的空间。
2. map
2.1 map创建
m = make(map[int]int) // 需要注意 make(map)返回的是一个指针
2.2 数据结构
type hmap {
count int
flags uint8 // map当前是否处于写入状态等
B uint8 // 2的B次幂表示当前map中桶的数量(buckets的长度)
noverlow uint16 // map中溢出桶的数量,当溢出桶太多时,map会进行等量扩容
hash0 uint32 //生成hash的随机数种子
buckets unsafe.Pointer //当前map对应的桶的指针
oldbuckets unsafe.Pointer // 扩容时的旧桶
nevacuate uintptr //扩容时,用于标记当前旧桶中小于nevacute的数据都已经转移到了新桶
extra *mapextra //存储map的溢出桶
}
Go中的map的数据都是存在bmap的数据结构中的,最多放8个kv对,溢出桶的设计与GC有关系,如果map为内联数据类型时,map数据结构里的指针就只有溢出桶了,这个时候就可以避免遍历map。
2.3 扩容机制
当我们插入一个k-v对时,需要确定他应该插入到bucket数组的哪一个槽中。bucket数组的长度为2^B,即2的次幂数,而2^B-1转换成二进制后一定是低位全1,高位全0的形式,因此在进行按位与操作后,一定能求得一个在[0,2^B-1]区间上的任意一个数,也就是数组中的下标位置,相较之下,能获得比取模更加优秀的执行效率。
涉及到扩容,每一次bucket数组都会变为现在的两倍,方便我们进行hash迁移。
map触发扩容的条件有两种:
- 负载因子大于6.5时(负载因子 = 键数量 / bucket数量)
- overflow的数量达到2^min(15,B)
等量扩容 所谓等量扩容,并不是扩大容量,而是bucket数量不变,重新做一遍类似增量扩容的搬迁动作,把松散的键值对重新排列一次,以使bucket的使用率更高,从而保证更快的存取速度。
3. channl
3.1 数据结构
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
elemtype *_type // element type
sendx uint // send index
recvx uint // receive index
recvq waitq // list of recv waiters
sendq waitq // list of send waiters
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}

3.2 过程详解
channl的入队与出队操作都是都是加锁的,以此来保证并发安全。当队列满了再插入数据时,插入线程g会进入wait状态并且挂在sendq队列上,等取出元素时会将其唤醒,空队取元素同理。
今天关于《go语言中slice,map,channl底层原理》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
Go语言使用对称加密的示例详解
- 上一篇
- Go语言使用对称加密的示例详解
- 下一篇
- goredis之redigo的使用
-
- 舒服的裙子
- 这篇博文太及时了,很详细,很棒,码住,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-03-02 15:58:57
-
- 耍酷的电话
- 这篇技术文章真是及时雨啊,太全面了,感谢大佬分享,已加入收藏夹了,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-02 19:06:11
-
- 高兴的魔镜
- 这篇文章真是及时雨啊,好细啊,感谢大佬分享,收藏了,关注楼主了!希望楼主能多写Golang相关的文章。
- 2023-01-01 13:22:04
-
- 老迟到的自行车
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享博文!
- 2023-01-01 12:53:19
-
- 酷炫的大象
- 这篇技术贴真是及时雨啊,很详细,很好,mark,关注作者了!希望作者能多写Golang相关的文章。
- 2023-01-01 12:29:34
-
- 潇洒的铅笔
- 这篇博文真是及时雨啊,太详细了,感谢大佬分享,码起来,关注老哥了!希望老哥能多写Golang相关的文章。
- 2022-12-31 22:35:12
-
- 小巧的黑米
- 太详细了,码住,感谢作者的这篇技术文章,我会继续支持!
- 2022-12-31 18:45:15
-
- 雪白的雪糕
- 太详细了,mark,感谢up主的这篇技术贴,我会继续支持!
- 2022-12-31 18:29:10
-
- 危机的河马
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢老哥分享技术贴!
- 2022-12-31 14:48:59
-
- Golang · Go教程 | 2小时前 | 错误处理 · regexp · Go教程 · 配置热加载 · Go regexp.Compile 正则表达式配置 配置错误处理
- Go regexp 编译正则失败时怎么把错误交给配置层
- 222浏览 收藏
-
- Golang · Go教程 | 3小时前 |
- Go regexp.FindAllStringSubmatchIndex 怎么映射捕获组位置
- 134浏览 收藏
-
- Golang · Go教程 | 3小时前 | go · 有理数 · 高精度计算 · 浮点误差 · math/big.Rat FloatString big.NewRat SetFrac64 SetString RatString
- Go math/big.Rat 怎么精确计算分数而不是浮点近似
- 312浏览 收藏
-
- Golang · Go教程 | 4小时前 |
- Go strconv.NumError 怎么拿到具体转换字段
- 301浏览 收藏
-
- Golang · Go教程 | 4小时前 |
- Go strconv.ParseFloat 遇到 NaN 和 Inf 怎么区分
- 501浏览 收藏
-
- Golang · Go教程 | 6小时前 | Timer · go · 性能优化 · time.After ·
- Go time.After 在高频循环中为什么会造成延迟对象堆积
- 313浏览 收藏
-
- Golang · Go教程 | 6小时前 |
- Go strconv.AppendQuote 怎么低分配地拼接带引号字符串
- 184浏览 收藏
-
- Golang · Go教程 | 7小时前 | 并发 · 定时器 · go · time.Timer time.NewTimer time.Stop time.Reset
- Go time.Timer 通道读不到事件时怎么判断定时器当前状态
- 173浏览 收藏
-
- Golang · Go教程 | 7小时前 | 定时任务 · 并发控制 · Go教程 · 资源释放 · Go Goroutine context 后台任务 time.Ticker Ticker.Stop
- Go time.Ticker 不再使用时怎么停止避免后台任务残留
- 297浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 52次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 204次使用
-
- C-Eval
- 深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
- 139次使用
-
- AI Prompt Library
- 探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
- 71次使用
-
- Generrated
- Generrated汇集9300+张DALL·E生成图像及对应提示词,支持查看完整图集、对比DALL·E 2与3版本差异,是AI绘图新手学习Prompt设计与获取创作灵感的实用工具。
- 51次使用
-
- Go map 并发写 panic 怎么办:从共享 map 到可控写入路径
- 2026-06-30 123浏览
-
- Goreflect反射原理示例详解
- 2022-12-22 174浏览
-
- 详解如何在Go语言中循环数据结构
- 2022-12-22 406浏览
-
- GoLangstrings.Builder底层实现方法详解
- 2022-12-22 418浏览
-
- GoLangchannel底层代码实现详解
- 2023-02-16 215浏览
