go语言map底层实现原理,golang map底层原理

go语言map底层实现原理,golang map底层原理,go语言中slice,map,channl底层原理

本文主要介绍了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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: