本文主要介绍了go语言中切片、映射和通道的基本原理。切片、映射和通道是我们Go语言中最常用的数据结构。需要更多相关内容的,可以参考下面文章的详细内容。
:
目录
0.前言1。创建Slice1.1Slice 1.2数据结构1.3扩展机制2。map2.1地图创建2.2数据结构2.3扩展机制3。通道3.1数据结构3.2流程细节
0. 前序
切片、映射和通道是我们Go语言中最常用的数据结构。深入了解它们,对于我们构建知识体系、优化代码都有着重要的意义。因此,在本文中,我们深入到这三种数据结构的底层,分析它们的设计思想。
1. slice
1.1 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底层数据结构如下:
类型{
数组不安全。指针//指针
len//现有长度
上限int //容量
}
在Go语言中,所有的参数传递都是值传递,slice也是。但由于它的底层指针,在它被转移到另一个函数后,仍然可以修改其地址对应位置的值。但是,当扩展操作发生时,会由于地址的重新分配而产生问题。这里我们将介绍slice的扩展机制。
1.3 扩容机制
当执行append()且cap不够时,会触发扩展操作(copy()操作不会触发扩展)。
容量的确定:
如果预期容量是当前容量的两倍以上,将使用预期容量;如果当前切片的长度小于1024,则容量加倍;如果当前切片的长度大于1024,则每次增加25%的容量,直到新容量大于预期容量;
以上是确定容量的初步步骤。当数据类型大小为1字节、8字节或2的倍数时,它将根据内存大小向上舍入,对齐内存,然后返回到新的扩展大小。
内存对齐的一个重要原因是Go在分配内存时是一个类似于伙伴系统的固定内存块,对齐这个内存可以最大化的利用分配的空间。
2. map
2.1 map创建
M=make(map[int]int) //注意make(map)返回一个指针。
2.2 数据结构
hmap标牌
count int
flagsint8//map当前是否处于写状态等。
uint8//2的b次方表示当前地图中的桶数(桶的长度)
noverlow uint16 //map中溢出桶的数量。当溢出桶过多时,map将按相同的量扩展容量。
hashui nt 32//生成哈希的随机数种子
水桶不安全。指针//对应于当前地图的桶的指针
旧桶不安全。指针//容量扩展期间的旧存储桶
evacuate uintptr//扩容时,用于标记当前旧桶小于nevacute的数据已经转移到新桶中。
Extra *mapextra //用于存储地图的溢出桶
}
Go中map的数据全部存储在bmap数据结构中,最多8 kv对。溢流桶的设计与GC有关。如果map是内联数据类型,那么map数据结构中的指针只有溢出桶,此时可以避免遍历map。
2.3 扩容机制
当我们插入一个k-v对时,我们需要确定它应该插入桶数组的哪个槽。桶数组的长度是2 b,也就是2的幂,2 b-1转换成二进制后必须是低位全1,高位全0的形式。所以经过按位and运算,我们肯定可以找到[0,2 b-1]区间内的任意一个数,也就是数组中的下标位置。通过比较,我们可以得到比模运算更好的执行效率。
说到扩容,桶数组每次都会翻倍,方便我们进行哈希迁移。
map触发扩容的条件有两种:
当加载因子大于6.5时(加载因子=键的数量/桶的数量),溢出的数量达到2分钟(15,b)
等量扩容所谓等量扩容,不是扩容,而是保持桶数不变。再次做类似增量扩容的重定位动作,将松散的键-值对重新排列一次,使桶的利用率更高,从而保证更快的访问速度。
3. channl
3.1 数据结构
hchan结构类型{
队列中的总数据量
循环队列的大小
但是不安全。指针//指向dataqsiz元素的数组
elemsize uint16
封闭式uint32
elemtype *_type //元素类型
sendx uint //发送索引
接收索引
recvq waitq //接收等待者列表
发送等待//发送等待列表
//lock保护hchan中的所有字段,以及几个
sudogs中的字段在此通道上被阻止。
//
//当持有此锁时,不要更改另一个G的状态
//(特别是,不要准备G),因为这可能会死锁
//堆栈收缩。
锁定互斥体
}
3.2 过程详解
通道的入队和出队操作都被锁定,以确保并发安全性。当队列已满,插入数据时,插入线程G会进入等待状态,挂在sendq队列上,取出元素时会唤醒。空队列获取元素也是如此。
关于go语言中切片、映射和通道的基本原理,本文到此结束。有关Go slice、map和channl的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。