admin 管理员组

文章数量: 1086019


2024年3月26日发(作者:职业规划的smart原则)

gomap的结构扩容规则

"go map" 是指 Golang 的 map 数据结构。它是一种无序的键值对集

合,其中每个键只能出现一次。在 Golang 中,map 是通过哈希表实现的,

因此在理解 map 的结构和扩容规则之前,我们需要先了解哈希表的基本

概念。

哈希表是一种利用哈希函数进行索引的数据结构,它能够在常数时间

内进行插入、删除和查找操作。在哈希表中,每个键值对都会通过哈希函

数计算出一个哈希值,然后根据哈希值找到对应的桶。每个桶中存储了若

干个键值对,哈希值相同的键值对会被放在同一个桶中,所以在进行查找

操作时只需要考虑同一个桶中的键值对。

Golang 的 map 结构也是基于哈希表实现的,它包含以下几个重要的

字段:

- count:记录当前 map 中存储的键值对个数。

- B:也被称为负载因子,默认值是6.5、负载因子是指哈希表中桶

的个数和最大可容纳的键值对个数的比值。当 count 超过 B 乘以桶的个

数时,就会触发扩容操作。

- buckets:存储了实际的桶结构。

- oldbuckets:用于在扩容时保存旧的桶结构。

接下来我们来看一下 map 扩容的规则,也就是当 count 超过一定阈

值时,map 是如何进行扩容的:

1. 首先,根据 B 的值计算新的桶的个数 newBuckets = count / B。

如果 newBuckets 小于 1,则新的桶个数为 1

2. 创建新的桶结构 newbuckets,并将其初始化为新的桶个数。

3.将旧桶结构中的键值对逐个重新计算哈希值,并将其放入新的桶结

构中对应的位置。这个过程被称为重新散列。

4. 在重新散列的过程中,如果新的桶个数大于旧的桶个数,那么新

创建的桶将直接保存在 newbuckets 中。

5. 否则,新创建的桶将被放入 oldbuckets 中,以便下次扩容时可

以继续使用。

需要注意的是,在重新散列的过程中,如果两个键的哈希值相同,那

么它们可能会被分配到同一个桶中。为了解决这个问题,每个桶中都维护

了一个链表,桶中的任意两个键值对都通过链表相连。

扩容操作可能会引发临界区,因为在扩容操作期间,有可能会有新的

写操作被并发地执行。为了保证在扩容期间的一致性和性能,Golang 采

用了一种叫做"shard locks"的机制。在扩容时,Golang 会将每个桶划分

为多个 shard,每个 shard 都绑定一个锁。当执行写操作时,只需要锁

定对应 shard 的锁,其他 shard 仍然可以并发地执行读操作。这种机制

既保证了一致性,又提高了性能。

总结起来,go map 的结构是基于哈希表实现的,包含 count、B、

buckets 和 oldbuckets等字段。在 count 超过负载因子时,map 会触

发扩容操作。扩容过程包括重新计算哈希值、重新散列和迁移桶等步骤。

为了保证一致性和性能,Golang 采用了 shard locks 机制来处理并发访

问的问题。

虽然上述解释已经超过了1200字,但希望能对你理解 go map 的结

构和扩容规则有所帮助。如果还有其他问题,欢迎继续提问!


本文标签: 扩容 操作 键值 过程 规则