关于Go语言的底层,Slice,map

1 Slice

Slice底层实现原理

切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象。因为基于数组实现,所以它的底层的内存是连续分配的,效率非常高,还可以通过索引获得数据,可以迭代以及垃圾回收优化。 切片本身并不是动态数组或者数组指针。它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。切片本身是一 个只读对象,其工作机制类似数组指针的一种封装。
切片对象非常小,是因为它是只有 3 个字段的数据结构:

  • 指向底层数组的指针
  • 切片的长度
  • 切片的容量

Slice扩容机制

在使用 append 向 slice 追加元素时,若 slice 空间不足则会发生扩容,扩容会重新分配一块更大的内存,将原 slice 拷贝到新 slice ,然后返回新 slice。扩容后再将数据追加进去。
扩容操作只对容量,扩容后的 slice 长度不变,容量变化规则如下:

若 slice 容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。
若 slice 容量够用,则将新元素追加进去,slice.len++,返回原 slice
若 slice 容量不够用,将 slice 先扩容,扩容得到新 slice,将新元素追加进新 slice,slice.len++,返回新 slice。

Slice与数组区别

array是固定长度的数组,使用前必须确定数组长度,是值类型。
slice是一个引用类型,是一个动态的指向数组切片的指针。
slice是一个不定长的,总是指向底层的数组array的数据结构,可以动态扩容。
创建方式不一样,Slice使用make创建或者根据数组创建。
作为函数参数时,数组传递的是数组的副本,而slice传递的是指针。

2 Map

Map底层实现原理

Golang 中 map 的底层实现是一个散列表,因此实现 map 的过程实际上就是实现散表的过程。在这个散列表中,主要出现的结构体有两个,一个叫 hmap(a header for a go map),一个叫 bmap(a bucket for a Go map,通常叫其 bucket)。
hmap 哈希表
hmap是Go map的底层实现,每个hmap内都含有多个bmap(buckets桶、oldbuckets旧桶、overflow溢出桶),既每个哈希表都由多个桶组成。

  • buckets buckets是一个指针,指向一个bmap数组,存储多个桶。
  • oldbuckets oldbuckets是一个指针,指向一个bmap数组,存储多个旧桶,用于扩容。
  • overflow
    overflow是一个指针,指向一个元素个数为2的数组,数组的类型是一个指针,指向一个slice,slice的元素是桶(bmap)的地址,这些桶都是溢出桶。为什么有两个?因为Go
    map在哈希冲突过多时,会发生扩容操作。[0]表示当前使用的溢出桶集合,[1]是在发生扩容时,保存了旧的溢出桶集合。overflow存在的意义在于防止溢出桶被gc。
  • bmap 哈希桶
    bmap是一个隶属于hmap的结构体,一个桶(bmap)可以存储8个键值对。如果有第9个键值对被分配到该桶,那就需要再创建一个桶,通过overflow指针将两个桶连接起来。在hmap中,多个bmap桶通过overflow指针相连,组成一个链表。

Map进行有序的排序

map每次遍历,都会从一个随机值序号的桶,再从其中随机的cell开始遍历,并且扩容后,原来桶中的key会落到其他桶中,本身就会造成失序
如果想顺序遍历map,先把key放到切片排序,再按照key的顺序遍历map。
或者可以先把map中的key,通过sort包排序,再遍历map。

map 为什么是不安全的

Go map 默认是并发不安全的,同时对 map 进行并发读写的时,程序会 panic,原因如下:Go 官方经过长时间的讨论,认为 map 适配的场景应该是简单的(不需要从多个 gorountine 中进行安全访问的),而不是为了小部分情况(并发访问),导致大部分程序付出锁的代价,因此决定了不支持。
map 在扩缩容时,需要进行数据迁移,迁移的过程并没有采用锁机制防止并发操作,而是会对某个标识位标记为 1,表示此时正在迁移数据。如果有其他 goroutine 对 map 也进行写操作,当它检测到标识位为 1 时,将会直接 panic。
如果想实现map线程安全,有两种方式:
方式一:使用读写锁 map + sync.RWMutex
方式二:使用golang提供的 sync.Map

Map扩容策略

扩容时机:
向 map 插入新 key 的时候,会进行条件检测,符合下面这 2 个条件,就会触发扩容
扩容条件:

超过负载 map元素个数 > 6.5(负载因子) * 桶个数

溢出桶太多

当桶总数<2^15时,如果溢出桶总数>=桶总数,则认为溢出桶过多
当桶总数>215时,如果溢出桶总数>=215,则认为溢出桶过多
扩容机制:

双倍扩容:针对条件1,新建一个buckets数组,新的buckets大小是原来的2倍,然后旧buckets数据搬迁到新的buckets。

等量扩容:针对条件2,并不扩大容量,buckets数量维持不变,重新做一遍类似双倍扩容的搬迁动作,把松散的键值对重新排列一次,使得同一个 bucket 中的 key 排列地更紧密,节省空间,提高 bucket 利用率,进而保证更快的存取。

渐进式扩容:
插入修改删除key的时候,都会尝试进行搬迁桶的工作,每次都会检查oldbucket是否nil,如果不是nil则每次搬迁2个桶,蚂蚁搬家一样渐进式扩容

Map和Slice区别

数组:数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。声明方式:var a [3]int
slice(切片):Slice(切片)代表变长的序列,序列中每个元素都有相同的类型,slice的语法和数组很像,只是没有固定长度而已。
map:在Go语言中,一个map就是一个哈希表的引用,是一个无序的key/value对的集合

Map总结

map是引用类型
map遍历是无序的
map是非线程安全的
map的哈希冲突解决方式是链表法
map的扩容不是一定会新增空间,也有可能是只是做了内存整理
map的迁移是逐步进行的,在每次赋值时,会做至少一次迁移工作
map中删除key,有可能导致出现很多空的kv,这会导致迁移操作,如果可以避免,尽量避免

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/100186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win1011安装MG-SOFT+MIB+Browser+v10b

文章目录 安装MG-SOFTSNMP服务配置安装MG-SOFT启动MIB-Browser以及错误解决MIB Browser使用 安装MG-SOFT win10和win11安装基本一样&#xff0c;所以参照下面的操作即可&#xff01; SNMP服务配置 打开设置&#xff0c;应用和功能&#xff0c;可选功能&#xff0c;选择添加功…

java项目中git的.ignore文件设置

在Git中&#xff0c;ignore是用来指定Git应该忽略的故意不被追踪的文件。它并不影响已经被Git追踪的文件。我们可以通过.ignore文件在Git中指定要忽略的文件。 当我们执行git add命令时&#xff0c;Git会检查.gitignore文件&#xff0c;并自动忽略这些文件和目录。这样可以避免…

归纳所猜半结论推出完整结论:CF1592F1

https://www.luogu.com.cn/problem/CF1592F1 场上猜了个结论&#xff0c;感觉只会操作1。然后被样例1hack了。然后就猜如果 ( n , m ) (n,m) (n,m) 为1则翻转4操作&#xff0c;被#14hack了。然后就猜4操作只会进行一次&#xff0c;然后就不知道怎么做下去了。 上面猜的结论都…

计算机网络 面试题

PART1 1.TCP和UDP的区别是什么&#xff1f; 2.TCP报文首部格式是什么&#xff1f; 3.TCP三次握手的过程 4.为什么TCP要三次握手&#xff1f; 5.TCP三次握手的数据报可以携带数据吗&#xff1f; 6.半连接队列是什么&#xff1f; 7.SYN 洪泛攻击是什么&#xff1f; 8.TCP…

PCL点云处理之Pcd文件读取、法线与曲率计算、多线程加速、属性字段合并 (二百零八)

PCL点云处理之Pcd文件读取、法线与曲率计算、多线程加速、属性字段合并(二百零八) 一、相关介绍二、算法实现1.代码一、相关介绍 (夜深人不静) 法线和曲率的计算是点云处理中常用的关键特征,PCL提供了特有的点类型PointNormal来记录这些信息,通过OMP多线程对相关的计算函…

数据源作用以及spring配置数据源

数据源 数据源&#xff0c;简单理解为数据源头&#xff0c;提供了应用程序所需要数据的位置。数据源保证了应用程序与目标数据之间交互的规范和协议&#xff0c;它可以是数据库&#xff0c;文件系统等等。其中数据源定义了位置信息&#xff0c;用户验证信息和交互时所需的一些…

Http请求响应 Ajax 过滤器

10/10/2023 近期总结&#xff1a; 最近学的后端部署&#xff0c;web服务器运行&#xff0c;各种请求响应&#xff0c;内容很多&#xff0c;学的很乱&#xff0c;还是需要好好整理&#xff0c;前面JavaSE内容还没有完全掌握&#xff0c;再加上一边刷题&#xff0c;感觉压力很大哈…

Postman接口测试学习之常用断言

什么是断言&#xff1f; 断言——就是结果中的特定属性或值与预期做对比&#xff0c;如果一致&#xff0c;则用例通过&#xff0c;如果不一致&#xff0c;断言失败&#xff0c;用例失败。断言&#xff0c;是一个完整测试用例所不可或缺的一部分&#xff0c;没有断言的测试用例…

285_C++_web提取AI告警信息JSON格式

struct Cache_t {AIAlarmFaceInfo Face;AIAlarmPlateInfo Plate;SAISnapedObjInfo Object;SharedCArray Common;int Type; };struct Client_t {Client_t() : AlarmCnt(HA

MAX30102心率血氧传感器

MAX30102心率血氧传感器介绍 背景基本功能基本结构基本原理采集方法直通式采集方法反射式采集方法 血氧采集原理Beer-Lambert 定理皮肤组织模型血氧测量过程AC / DC 的计算 心率采集原理 实验结果代码走读资源链接 背景 目前&#xff0c;基本上所有的可穿戴式设备都集成了心率…

【Codeforces】 CF1762E Tree Sum

题目链接 CF方向 Luogu方向 题目解法 首先考虑 n n n 为奇数的情况无解&#xff0c;这个可以通过乘积矛盾简单证明 接下来考虑一个结论是&#xff1a;偶数个点的树的形态确定之后&#xff0c;只有恰好 1 1 1 种染色方案&#xff0c;即从叶子一层一层往上面染&#xff0c;…

【Java 进阶篇】CSS盒子模型详解

CSS盒子模型是网页布局的基础之一&#xff0c;它定义了HTML元素在页面上的占用空间和相互关系。理解CSS盒子模型对于构建各种类型的网页布局至关重要。在本文中&#xff0c;我们将深入探讨CSS盒子模型的各个方面&#xff0c;包括盒子模型的概念、属性和如何使用它们来控制元素的…

爬虫进阶-反爬破解6(Nodejs+Puppeteer实现登陆官网+实现滑动验证码全自动识别)

一、NodejsPuppeteer实现登陆官网 1.环境说明 Nodejs——直接从官网下载最新版本&#xff0c;并安装 使用npm安装puppeteer:npm install puppeteer npm install xxx -registry https://registry.npm.taobao.org Chromium会自动下载&#xff0c;前提是网络通畅 2.实践操作…

[idekCTF 2022]Paywall - LFI+伪协议+filter_chain

[idekCTF 2022]Paywall 一、解题流程&#xff08;一&#xff09;、分析&#xff08;二&#xff09;、解题 二、思考总结 一、解题流程 &#xff08;一&#xff09;、分析 点击source可以看到源码&#xff0c;其中关键部分&#xff1a;if (isset($_GET[p])) {$article_content…

JVM 参数

JVM 参数类型大致分为以下几类&#xff1a; 标准参数&#xff08;-&#xff09;&#xff1a;保证在所有的 JVM 实现都支持的参数非标准参数&#xff08;-X&#xff09;&#xff1a;通用的&#xff0c;特定于 HotSpot 虚拟机的参数&#xff0c;这些参数不保证在所有 JVM 实现中…

睿伴科创上线了

Robotutor睿伴&#xff0c;一个专业的青少儿编程科创教育品牌和科创服务平台。 Robotutor睿伴拥有一个超过5年的青少儿编程科创教育团队&#xff0c;积累了丰富的课程研发&#xff0c;教学服务和赛事辅导经验。并和上海多所知名高校、上海市计算机学会、上海青少年科学社等开展…

nvidia 驱动问题

https://stackoverflow.com/questions/43022843/nvidia-nvml-driver-library-version-mismatch https://zhuanlan.zhihu.com/p/643773939

【【萌新的SOC学习之重新起航SOC】】

萌新的SOC学习之重新起航SOC ZYNQ PL 部分等价于 Xilinx 7 系列 FPGA PS端&#xff1a;Zynq 实际上是一个以处理器为核心的系统&#xff0c;PL 部分可以看作是它的一个外设。 我们可以通过使用AXI(Advanced eXtensible Interface)接口的方式调用 IP 核&#xff0c;系统通过 AX…

1700*C. Mixing Water(数学 | 二分)

Problem - 1359C - Codeforces 解析&#xff1a; 因为每次先加热水&#xff0c;再加凉水&#xff0c;所以温度的范围肯定在 [ ( hc ) / 2 , h ] 所以当 t 为 h时&#xff0c;结果为 1 当 t 小于( hc ) / 2时&#xff0c;肯定为2 &#xff08;一杯热水和一杯冷水&#xff09; …