😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
author-avatar

GOLANG ROADMAP


首页
Go友会
  • 城市
  • 校园
Go学院
  • Go小课
  • Go小考
  • Go实战
  • 精品课
Go求职
  • 求职辅导🔥
  • Offer收割社群
  • 企业题库
  • 面试宝典
Go宝典
  • 在线宝典
  • B站精选
  • 推荐图书
  • 每日博文
Go仓库
实验区
  • Go周边
  • Go下载
  • Go月刊
消息
更多
  • 用户中心

    • 我的信息
    • 推广返利
  • 玩转星球

    • 星球介绍
    • 角色体系
    • 星主权益
  • 支持与服务

    • 联系星主
    • 成长记录
    • 常见问题
    • 吐槽专区
  • 合作交流

    • 渠道合作
    • 课程入驻
    • 友情链接
  • Go真实面试题汇总系列

    • 《Map篇》
  • 宝典内容

    • 33. 如何实现一个线程安全的 map?
    • 35. Go map 的底层实现 ?
    • 37. map的key可以是哪些类型?可以嵌套map吗?
    • 39. 讲一下set的原理,Java 的HashMap和 go 的map底层原理
    • 53. go的map是线程安全的吗?
    • 87. go map并发安全问题,如何解决
    • 150. map遍历的时候每次顺序都是固定的吗?为什么?
    • 159. go的sync.Map了解吗
    • 166. golang中两个map对象如何比较。
    • 206. map如何顺序读取?
    • 227. gomap结构,并发安全否
    • 231. go的hashmap如何实现的
    • 243. go 的 map 与 sync.map
    • 250. sync.map与map的区别
    • 255. Go map的底层原理
    • 265. Map是线程安全的吗?怎么解决并发安全问题?
    • 266. sync.Map 怎么解决线程安全问题?看过源码吗?
    • 272. 问了sync.Map(我说我对sync.Pool比较熟,就说Pool了)
    • 278. map什么内容不能为key
    • 279. map和sync.Map
    • 287. 说一说go中的map
    • 288. map的优缺点,以及改进?
    • 290. go中的map?分段锁拆了几个分片?
    • 345. 借助额外的数据结构比如slice等,对key进行排序,遍历slice得到顺序输出
    • 351. go的map的底层数据结构,查询复杂度
    • 397. Go一般怎么取map?
    • 398.如果一个map没申请空间,去向里面取值,会发生什么情况
    • 401. go中如何使遍历map变得有序
    • 427. map取一个key,然后修改这个值,原map数据的值会不会变化,根据map存储的类型回答
    • 432. 实现map的方法除了哈希还有哪些?
    • 468. go map slice 实现(内存泄漏分析)

😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

227. gomap结构,并发安全否


企业题库解析小组

题目序号:(2323)

题目来源:滴滴

频次:1

# 答案1:(ORVR)

Go中Map是一个KV对集合。底层使用hash table,用链表来解决冲突 ,出现冲突时,不是每一个Key都申请一个结构通过链表串起来,而是以bmap为最小粒度挂载,一个bmap可以放8个kv。

在哈希函数的选择上,会在程序启动时,检测 cpu 是否支持 aes,如果支持,则使用aes hash,否则使用memhash。

hash函数,有加密型和非加密型。加密型的一般用于加密数据、数字摘要等,典型代表就是md5、sha1、sha256、aes256 这种,非加密型的一般就是查找。

在map的应用场景中,用的是查找。

选择hash函数主要考察的是两点:性能、碰撞概率。

每个map的底层结构是hmap,是有若干个结构为bmap的bucket组成的数组。每个bucket底层都采用链表结构。

// A header for a Go map.

type hmap struct {

// 元素个数,调用 len(map) 时,直接返回此值

    count int

    flags uint8

    // buckets 的对数 log_2

    B uint8

    // overflow 的 bucket 近似数

    noverflow uint16

    // 计算 key 的哈希的时候会传入哈希函数

    hash0 uint32

    // 指向 buckets 数组,大小为 2^B

    // 如果元素个数为0,就为 nil

    buckets unsafe.Pointer

    // 扩容的时候,buckets 长度会是 oldbuckets 的两倍

    oldbuckets unsafe.Pointer

    // 指示扩容进度,小于此地址的 buckets 迁移完成

    nevacuate uintptr

    extra *mapextra // optional fields

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

bmap 就是我们常说的“桶”,桶里面会最多装 8 个 key,这些 key之所以会落入同一个桶,是因为它们经过哈希计算后,哈希结果是“一类”的,关于key的定位我们在map的查询和赋值中详细说明。

在桶内,又会根据key计算出来的hash值的高8位来决定 key到底落入桶内的哪个位置(一个桶内最多有8个位置)。

当map的key和value都不是指针,并且 size都小于128字节的情况下,会把bmap标记为不含指针,这样可以避免gc时扫描整个hmap。

但是,我们看bmap其实有一个overflow的字段,是指针类型的,破坏了 bmap 不含指针的设想,这时会把overflow移动到 hmap的extra 字段来。

这样随着哈希表存储的数据逐渐增多,我们会扩容哈希表或者使用额外的桶存储溢出的数据,不会让单个桶中的数据超过 8 个,不过溢出桶只是临时的解决方案,创建过多的溢出桶最终也会导致哈希的扩容。

go的map本身是不支持并发安全的,在查找、赋值、遍历、删除的过程中都会检测写标志,一旦发现写标志置位(等于1),则直接 panic。赋值和删除函数在检测完写标志是复位之后,先将写标志位置位,才会进行之后的操作。

  • 答案1:(ORVR)