【Go】 map 精髓理解

news2024/11/24 17:42:43
map

go map 的底层结构 hmap,的四个元素
然后再讲一下 buckets 的元素,讲一下 hash 冲突,和解决方法
再讲一下,增量扩容和等量扩容
再讲一下增删改查的过程,就查询过程

map 基础

向值为 nil 的 map 添加元素会发生 panic,说白了就是给声明但是没初始化的map添加元素
查询时候,如果没这个元素,会返回对应的零值,例如 int 的零值 0
一开始用 make 初始化时候,指定容量,可以有效的减少内存分配的次数,提升性能
查询语法if v, ok := m[“apple”];ok {}
删除语法:delete(m,“apple”) 空也不报错
添加和修改是一样的就是:m[“apple”] = “red”
len 也可以查长度
不是原子性的,并发不安全,多个协程同时操作一个 map 会产生读写冲突,panic,不过可以通过加锁或者 sync.map 实现并发安全

实现原理

1、数据结构

使用 Hash 表作为底层实现,一个 Hash 表可以有多个 bucket,每个 bucket 保存了一个或多个键值对,像,redis 是默认一个,go 是6.5个,多了会扩容
我们常说的 hash 桶就是 bucket,
在这里插入图片描述

type Map struct {
	Key  *Type
	Elem *Type
	Bucket *Type
	Hmap   *Type
	Hiter  *Type
}

// hmap 简化版本
type hmap struct {
	count     int   // 元素个数,kv个数
	B         uint8 // bucket 数组大小,其实就是 bmap
	buckets    unsafe.Pointer // 指针指向 bucket 数组,数组长 2 的 B 次方
	oldbuckets unsafe.Pointer // 老旧 bucket 数组,用于扩容
  ......
}

type bmap struct {
  tophash [bucketCnt]uint8 // 存储 hash 值的高 8 位,就是长度为 8 的整型数组
  date []byte // kkkkkkvvvvvv数据,这样可以节省内存,避免了内存对齐
  overflow *bmap // 溢出 bucket 的地址,指向了下一个 bucket 将冲突的键连接起来
}

2、hash 冲突

当两个或以上数量的键被 hash 到同一个 bucket 时候,我们称这些键发生了冲突
Go 使用了链地址法解决冲突
因为每个 bucket 可以存放八个键值对,当同一个 bucket 存放超过 8 个键值对时候就会创建一个 bucket,用类似链表的方式将 bucket 连接起来,使用 *bucket 指向溢出的那部分

3、负载因子

负载因子 = 键数量 / bucket 数量
负载因子过大过小都不好
-过小,空间利用率较小
-过大,冲突严重,存取效率低

当负载因子过大,需要申请更多的 bucket 并且对所有的键值对重新排列,使其均匀的分配在 bucket,这个过程叫 rehash
每个 hash 表对负载因子的容忍度大小不一样,go 6.5 因为go的 bucket 可以存八个,redis 是1个

4、扩容

扩容有增量扩容,和等量扩容,都是对于负载因子过大的情况,对 go 就是当一个 bucket 有7/8个元素时候
增量扩容:
会新建一个 bucket ,新的 bucket 大小是原来两倍,然后把旧的 bucket 数组中的数据逐渐的搬迁到新的 bucket 数组
不过可能出现一个情况,当有数亿个元素时候,考虑到一次性搬迁会有很大延时,所有 go 用逐级搬迁策略,就是每次访问 map 都会搬迁一下,两个键值对
那它是如何处理数组指针呢?就是让 hmap 中 oldbuckets 指针指向原 buckets 数组,然后申请新的 buckets 数组,长度为原来两倍,之后的迁移工作就是将 oldbuckets 元素逐渐搬迁到新的 buckets ,搬迁完毕就可以释放 oldbuckets 数组
等量扩容:
这个不扩容,甚至内存释放了一些,意思是,不扩容的情况下,实行了类似增量扩容中搬迁的动作
因为在某些情况下,极端情况,我们删除了一些元素,很多哈,导致最后的元素集中于一个 bucket ,而这个 bucket 有很多的溢出 bucket 桶,删除后这些桶都空了,这时候等量扩容,就是使得 bucket 数量不变,但是重新组织后的 overflow 的 Bucket 数量减少,节省了空间,提高了查询效率

5、查询

查询就是:根据键的 Hash 值确定一个 bucket ,查它看有没有该元素
查询:
根据 key 值计算 Hash 值
取 Hash 值低位与 hmap.B 取模确定 bucket 位置
取 Hash 值高位,在 tophash 数组查询,如果tophash[i]的hash值与计算的一样,就去获取 tophash[i] 的key值
当前 bucket 没找到就去溢出bucket找
如果当前处于搬迁中,优先从 oldbucket 找
那么添加删除都差不多了,就不赘述了

参考自:《Go 专家编程》

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

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

相关文章

青枫壁纸小程序V1.4.0(后端SpringBoot)

引言 那么距离上次的更新已经过去了5个多月,期间因为忙着毕业设计的原因,更新的速度变缓了许多。所以,这次的更新无论是界面UI、用户功能、后台功能都有了非常大的区别。希望这次更新可以给用户带来更加好的使用体验 因为热爱,更…

【湍流介质的三维传播模拟器】全衍射3-D传播模拟器,用于在具有随机和背景结构的介质中传播无线电和光传播(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码实现 💥1 概述 全衍射3-D传播模拟器是一种用于模拟在具有随机和背景结构的介质中传播无线电和光的工具。它可以帮助研究人员和工程师理解和预测无线电波和光波…

多重感知机MLP:Mnist

文章目录 网络结构代码common_utils.pynetwork.pyprovider.pytrain.pytest.pyvisual.py 实验训练结果测试结果可视化 网络结构 输入过程输出28*28Flatten784784Linear300300Linear100100Linear10 代码 文件结构: common_utils.py 用来输出日志文件 # common_…

基于扩展(EKF)和无迹卡尔曼滤波(UKF)的电力系统动态状态估计

1 主要内容 该程序对应文章《Power System Dynamic State Estimation Using Extended and Unscented Kalman Filters》,电力系统状态的准确估计对于提高电力系统的可靠性、弹性、安全性和稳定性具有重要意义,虽然近年来测量设备和传输技术的发展大大降低…

Linux常用嗅探工具(1):fping命令

fping的优点: 可以一次ping多个主机可以从主机列表文件ping结果清晰 便于脚本处理速度快 fping的安装: 前置安装cgg编译器 : yum -y install gcc 下载fping: wget http://fping.org/dist/fping-4.0.tar.gz 解压: …

力扣 -- 918. 环形子数组的最大和

一、题目: 题目链接:918. 环形子数组的最大和 - 力扣(LeetCode) 二、解题步骤: 下面是用动态规划的思想解决这道题的过程,相信各位小伙伴都能看懂并且掌握这道经典的动规题目滴。 三、参考代码&#xff1…

Redis 基础知识和核心概念解析:探索 Redis 的数据结构与存储方式

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

F---图像识别---河南省第十三届ICPC大学生程序设计竞赛

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 输入 10 10 ........*. ........*. ........*. ........*. ....#...*. ........*. ........*. ********** ........*. ........*. 输出 -4 3 解析: 遍历整个二维数组&#xff0…

dubbo从基于注解方式转为基于xml配置方式的使用心得

过程中遇到的问题百分之九十九的问题都是因为版本不兼容问题,所以在引入依赖的时候要注意这点,可以从maven central repository官方仓库这里看所要引用版本与其可兼容的版本

畅想未来感汽车HMI设计的奇妙之旅!

当下智能电动汽车的发展势头越来越高涨,与智能电动汽车相关的汽车HMI设计也成为各个品牌重点发力的地方,汽车HMI设计正在前所未有的新高度,本篇文章就来聊聊HMI设计的那些事 ⬇⬇⬇点击获取更多设计资源 https://js.design/community?categ…

prometheus监控mysql8.x以及主从监控告警

mysql8.x主从部署请看下面文档 docker和yum安装的都有 Docker部署mysql8.x版本互为主从_争取不加班!的博客-CSDN博客 Mysql8.x版本主从加读写分离(一) mysql8.x主从_myswl8双主一从读写分离_争取不加班!的博客-CSDN博客 安装部署…

C++OpenCV(4):图像截取与掩膜操作

🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 🔆 OpenCV项目地址及源代码:点击这里 文章目录 图像截取图像掩膜操作 图像截取 ROI操作,指的是:region of interest,感兴趣区域。 我们可以对一张…

Vue 项目增加版本号输出, 可用于验证是否更新成功

webpack 1. vue.config.js 中增加以下配置, 此处以增加一个日期时间字符串为例, 具体内容可以根据自己需求自定义 // vue.config.js module.exports {chainWebpack(config) {config.plugin(define).tap(args > {args[0][process.env].APP_VERSION ${JSON.stringify(new …

行为型模式--模版方法模式(图文详解)

模版方法模式--图文详解 采摘机器人-场景体验模版方法模式-解决问题模版方法模式-定义优缺点优点缺点 采摘机器人-场景体验 今天看抖音上外国开始使用采摘苹果的机器人,我们模仿一下的他的大体流程: 主体采摘车进入苹果园进入苹果指定采摘地点&#xf…

通过自动化单元测试的形式守护系统架构

目录 0前言 1 背景 2 为什么选择 Archunit 3 Archunit 是什么 4 引入 Archunit 4.1 开始就是如此简单 4.2 如何组织架构规则 4.3 团队如何规范化 0前言 通过自动化单元测试的形式守护系统架构是一种有效的方式,可以确保系统在不断演进和修改的过程中保持稳…

Python实战之数据挖掘详解

一、Python数据挖掘 1.1 数据挖掘是什么? 数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,通过算法,找出其中的规律、知识、信息的过程。Python作为一门广泛应用的编程语言,拥有丰富的数据挖掘库&#…

数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病...

全文链接:http://tecdat.cn/?p23061 这个数据集(查看文末了解数据免费获取方式)可以追溯到1988年,由四个数据库组成。克利夫兰、匈牙利、瑞士和长滩。"目标 "字段是指病人是否有心脏病。它的数值为整数,0无…

盖子的c++小课堂——第二十讲:动态规划

前言 中间呢其实还有两讲,但是那两讲太easy了,根本难不倒你们,所以,我索性不放了~~那我们今天讲一个比较容易的知识点——动态规划(终于没人给我催更了!哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈…

IOC控制反转--.net framework

IOC控制反转–.net framework 分层架构: 一、传统依赖倒置实现 传统工艺:会有依赖,上端全部展示细节 BaseBll baseBll new BaseBll(); baseBll.DoSomething();依赖于抽象:左边依赖倒置,面向抽象 实现类继承接口&am…

React18和React16合成事件原理(附图)

💡 React18合成事件的处理原理 “绝对不是”给当前元素基于addEventListener做的事件绑定,React中的合成事件,都是基于“事件委托”处理的! 在React17及以后版本,都是委托给#root这个容器(捕获和冒泡都做了…