go map 映射

 1、数据结构


// A header for a Go map.
type hmap struct {// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.// Make sure this stays in sync with the compiler's definition.count     int // # live cells == size of map.  Must be first (used by len() builtin)flags     uint8B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for detailshash0     uint32 // hash seedbuckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growingnevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)extra *mapextra // optional fields
}// mapextra holds fields that are not present on all maps.
type mapextra struct {// If both key and elem do not contain pointers and are inline, then we mark bucket// type as containing no pointers. This avoids scanning such maps.// However, bmap.overflow is a pointer. In order to keep overflow buckets// alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow.// overflow and oldoverflow are only used if key and elem do not contain pointers.// overflow contains overflow buckets for hmap.buckets.// oldoverflow contains overflow buckets for hmap.oldbuckets.// The indirection allows to store a pointer to the slice in hiter.overflow    *[]*bmapoldoverflow *[]*bmap// nextOverflow holds a pointer to a free overflow bucket.nextOverflow *bmap
}// A bucket for a Go map.
type bmap struct {// tophash generally contains the top byte of the hash value// for each key in this bucket. If tophash[0] < minTopHash,// tophash[0] is a bucket evacuation state instead.tophash [abi.MapBucketCount]uint8// Followed by bucketCnt keys and then bucketCnt elems.// NOTE: packing all the keys together and then all the elems together makes the// code a bit more complicated than alternating key/elem/key/elem/... but it allows// us to eliminate padding which would be needed for, e.g., map[int64]int8.// Followed by an overflow pointer.
}

map 的底层结构包含以下几个重要的元素:

  • hmaphmap 是 Go 中 map 类型的实际数据结构,它包含了哈希表的核心信息。例如,桶的指针、大小、负载因子、哈希函数等。
  • B:2^B 代表桶的数量,初始时B=3,即桶数量为8。

  • bucketsbuckets 数组存储了 map 中的哈希桶,每个桶内存储着一部分键值对。如果哈希冲突较多,桶会存储多个键值对。

  • oldbuckets:旧桶数组

  • noverflow:代表溢出桶的数量

  • nevacuate:扩容进度,指向旧桶中某个位置

  • overflow: 为了处理大量的哈希冲突,Go 中的哈希桶通常还会有一个 overflow 字段,表示某些冲突较严重的元素会被溢出到其他位置。

 2、底层实现

(1)哈希表和桶的结构

        Go 语言的 map 底层实现是一个哈希表,通过链地址法(数组加链表)来解决冲突,它的每个单元是一个桶。它的数组是由一组桶组成,每个桶是一个链式结构,可以存储8个键值对,当发生hash冲突时首先存在桶内,如果桶满了,就在桶后面连接溢出桶来存储键值对。

(2)哈希函数

        Go 使用一个高效的哈希函数将键映射到桶的位置。不同类型的键使用不同的哈希函数,例如字符串和整数会有不同的哈希计算方法。

(3)扩容和负载因子

        负载因子为6.5,代表键值对数量与桶数量比值的上限。如果达到负载因子值或溢出桶的数量超过正常桶的数量(或者超过上限值1<<15),就会发生扩容,新的桶数量是原来的2倍数。(负载因子的计算和桶的倍数不考虑溢出桶的数量)

        Go 的 map 底层哈希表设计采用了渐进式扩容的策略,当扩容时,并不是所有的键值对都会立刻重新哈希。Go 会 分批次地、渐进地将老桶中的元素迁移到新桶中,避免在扩容过程中产生性能瓶颈。

3、常用方法

(1)创建

var mp map[string]string // nil

mp := make(map[string]string) // empty map

(2)获取元素

v := m[key],key不存在时,获取的是零值

(3)判断key是否存在

v, ok := m[key]

(4)删除元素

delete(map[key])

func example() {var mp1 map[string]string                 // nilfmt.Println(mp1, mp1 == nil, len(mp1))    // map[] true 0var mp2 = make(map[string]string)         // empty mapfmt.Println(mp2, mp2 == nil, len(mp2))    // map[] false 0mp2["1"] = "1"mp2["2"] = "2"fmt.Println(mp2, mp2 == nil, len(mp2))    // map[1:1 2:2] false 2delete(mp2, "1")fmt.Println(mp2, mp2 == nil, len(mp2))    // map[2:2] false 1
}

4、使用map的注意事项

(1)键必须是可比较的类型
  • 可比较类型:键必须是可比较的类型,即支持 == 和 != 运算符。常见的可比较类型包括基本类型(如 intstringbool)、指针类型、接口类型、固定长度的数组类型以及所有字段都是可比较的结构体类型。
  • 不可比较类型:切片、映射、函数和通道类型是不可比较的,因此不能作为 map 的键。
(2)键的性能
  • 散列函数map 内部使用散列表实现,键的散列函数对性能有影响。选择合适的键类型可以提高查找和插入的效率。
  • 复杂键:如果键是复杂的结构体或大对象,计算散列值可能会比较慢,影响性能。在这种情况下,可以考虑使用更简单的键类型或优化散列函数。
(3)并发安全

  map不是并发安全的。如果多个 goroutine 同时读写同一个 map,会导致运行时错误。可以使用互斥锁(sync.Mutex 或 sync.RWMutex)来保护 map,或者使用 sync.Map 提供的并发安全版本的 map

(4)初始化和容量
  • 初始化:可以使用 make 函数初始化 map,并指定初始容量
  • 容量:初始容量可以提高性能,特别是在已知 map 大小的情况下
(5)键的默认值
  • 零值:访问 map 中不存在的键时,会返回该类型的零值。例如,对于 map[string]int,访问不存在的键会返回 0
  • 存在性检查:使用多值赋值来检查键是否存在
(6)键的内存管理
  • 指针键:使用指针作为键时,要特别注意指针的生命周期。如果指针指向的对象在 map 的生命周期内被修改或释放,可能会导致未定义行为。
  • 垃圾回收map 中的键和值都会被垃圾回收器管理。如果键或值不再被引用,垃圾回收器会自动回收它们占用的内存

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

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

相关文章

MySQL:left join后用on与where的区别

一、前言 前几天项目中&#xff0c;写SQL时本想通过 A left B join on and 后面的条件来使查出的两条记录变成一条&#xff0c;奈何发现还是有两条。在此记录一下&#xff0c;on与where的区别。 二、ON 原始数据展示 SELECT t1.*,t2.* FROM t_test_staff t1 left join t_te…

Unity 性能优化方案

‌Unity性能优化的主要方案包括以下几个方面‌&#xff1a; 一、减少Draw Call‌ Draw Call就是CPU调用图形编程接口&#xff0c;是CPU向GPU发送的命令 1.CPU和GPU并行工作的原理 CPU和GPU工作有一个命令缓冲区(Command Buffer) 命令缓冲区包含了一个命令队列&#xff0c;由C…

Spark 核心概念与宽窄依赖的详细解析

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…

快速删除图片脚本

电脑上存了几百万张小图片,让电脑慢慢删除了5个小时还没有删完,就写了一个python脚本,开启多线程删除,调整线程数量,让CPU和硬盘占有率都到100%,1个小时就删除了.感谢这段代码哈. 逻辑为删除当前目录下所有二级子目录中的文件&#xff0c;每个二级子目录由一个线程处理,每当一个…

【树莓派raspberrypi烧录Ubuntu远程桌面登入树莓派】

提示&#xff1a;本文利用的是Ubuntu主机和树莓派4B开发板&#xff0c;示例仅供参考 文章目录 一、树莓派系统安装下载前准备工作下载安装树莓派的官方烧录软件imagerimager的使用方法 二、主机与树莓SSH连接查看数梅派IP地址建立ssh连接更新树莓派源地址 三、主机端远程桌面配…

MySQL数据库专栏(四)MySQL数据库链接操作C#篇

摘要 本篇文章主要介绍C#链接MySQL数据库的接口介绍&#xff0c;使用实例及注意事项&#xff0c;辅助类的封装及调用实例&#xff0c;可以直接移植到项目里面使用。 目录 1、添加引用 2、接口介绍 2.1、MySqlConnection 2.2、MySqlCommand 2.3、MySqlDataReader…

百度世界2024:AI应用的浪潮时刻

百度AI公式&#xff1a;“技术商业社会”。 作者|金豫 编辑|杨舟 互联网行业正迈入增长瓶颈期&#xff0c;这一点从主要科技巨头&#xff0c;如Meta、Alphabet、腾讯等近年来的表现中可见端倪&#xff1a;广告收入增速放缓&#xff0c;市场渗透率接近饱和。 单纯依赖流量获取…

Linux 通过nmcli配置网络并配置bond(网卡绑定)

Linux 通过nmcli配置网络并配置bond Linux 通过nmcli配置网络并配置bond1. 什么是 Bond 网卡绑定2. Bond 网卡绑定的常见模式3. 通过nmcli配置网络并做网卡绑定 Linux 通过nmcli配置网络并配置bond 1. 什么是 Bond 网卡绑定 Bond 网卡绑定&#xff08;或 NIC Bonding&#xff…

PCL 点云拟合 最小二乘法拟合平面

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1计算点云质心 2.1.2最小二乘法拟合平面 2.1.3可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更新) 一…

【Stable Diffusion - Ai】小白入门必看(想控制AI的绘画结果?ControlNet 预处理篇)!真材实料!不卖课!!!

【Stable Diffusion - Ai】小白入门必看&#xff08;想控制AI的绘画结果&#xff1f;ControlNet 预处理篇&#xff09;&#xff01;真材实料&#xff01;不卖课&#xff01;&#xff01;&#xff01; 对于ControlNet来说&#xff0c;很多人都会感觉到陌生&#xff1b;这个插件…

几何合理的分片段感知的3D分子生成 FragGen - 评测

FragGen 来源于 2024 年 3 月 25 日 预印本的文章&#xff0c;文章题目是 Deep Geometry Handling and Fragment-wise Molecular 3D Graph Generation&#xff0c; 作者是 Odin Zhang&#xff0c;侯廷军&#xff0c;浙江大学药学院。FragGen 是一个基于分子片段的 3D 分子生成模…

Mysql事务中的一些问题,还有解决方法原理(ACID、脏读幻读重复读、next-key)

** 首先&#xff0c;事务是什么&#xff1f; ** 是一系列或者一组sql操作看作一个整体&#xff0c;作为一个事务&#xff0c;这一组sql要么都执行&#xff0c;要么都不执行。当所有sql都能执行成功的时候&#xff0c;commit当前事务&#xff0c;当其中一个sql出现问题时&…

【设计模式系列】享元模式(十五)

目录 一、什么是享元模式 二、享元模式的角色 三、享元模式的典型应用场景 四、享元模式在ThreadPoolExecutor中的应用 1. 享元对象&#xff08;Flyweight&#xff09;- 工作线程&#xff08;Worker&#xff09; 2. 享元工厂&#xff08;Flyweight Factory&#xff09;- …

为什么分布式光伏规模是6MW为界点

安科瑞 华楠 近日&#xff0c;能源局发布定义分布式光伏6MW及以上的光伏电站必须自发自用&#xff0c;自行消纳。多省能源局规定大于6MW的电站必须按集中式管理&#xff0c;另外大于6MW&#xff08;包含&#xff09;要省级审批&#xff0c;小于则由市级审批&#xff0c;10kV线…

RDD 算子全面解析:从基础到进阶与面试要点

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…

如何利用 CAS 实现原子操作:深入浅出原子类与线程安全

在并发编程中&#xff0c;确保线程安全是一个重要话题。为了避免多个线程对同一数据进行竞争访问&#xff0c;Java 提供了原子类&#xff08;Atomic Classes&#xff09;来保证并发场景下的线程安全&#xff0c;而原子类最核心的实现机制就是 CAS&#xff08;Compare And Swap&…

四万字长文SpringBoot、Spring、SpringMVC等相关面试题(注:该篇博客将会持续维护 最新维护时间:2024年11月12日)

&#x1f9f8;本篇博客重在讲解SpringBoot、Spring、SpringMVC等相关面试题&#xff0c;将会实时更新&#xff0c;欢迎大家添加作者文末联系方式交流 &#x1f4dc;JAVA面试题专栏&#xff1a;JAVA崭新面试题——2024版_dream_ready的博客-CSDN博客 &#x1f4dc;作者首页&…

02_ElementUI

一.前端工程化 1.1 概述 前端工程化是使用软件工程的方法来单独解决前端的开发流程 中模块化、组件化、规范化、自动化的问题,其主要目的为了 提高效率和降低成本。 1.2 NodeJS的安装 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环 境&#xff0c;可以使 JavaS…

关于Unity使用LookAt时为什么不能旋转

使用LookAt会使物体的Z轴对准某坐标 但是X和Y轴也是定死的&#xff0c;所以这个时候你再旋转也就没有效果了 解决方法&#xff1a; 使用辅助空物体&#xff1a; 可以创建一个空物体作为父节点&#xff0c;将其对准目标位置&#xff08;使用 LookAt&#xff09;&#xff0c;…

三、运算符、数据类型转换(显式、隐式)、语句(if、三元、switch、while、for)

1. 运算符 1.1 自增自减 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> &…