返回

Go 语言的 sync.Map 详解(二):更深入地探究 entry

后端

在上一篇文章《大白话讲讲 Go 语言的 sync.Map(一)》中,我们简要介绍了 entry 数据结构,并阐述了 Go 语言标准库中 map 不是线程安全的原因,以及 sync.Map 如何通过引入一层抽象来回避这个问题。在这篇文章中,我们将深入探究 entry 的内部机制,了解它如何在提升性能和确保并发安全方面发挥至关重要的作用。

entry 的结构

sync.Map 的 entry 是一个包含键值对和锁的结构体。锁用于保护键值对,防止在并发访问时发生数据竞争。entry 结构如下:

type entry struct {
    key    interface{}
    value  interface{}
    next   *entry
    expire int64
}
  • key: 键,可以是任意类型的对象。
  • value: 值,可以是任意类型的对象。
  • next: 指向下一个 entry 的指针,用于形成链表。
  • expire: 用于实现过期机制的字段,本篇文章不会讨论过期机制。

哈希表和链表

sync.Map 使用哈希表来存储 entry。哈希表是一个数组,其中每个元素都是一个链表。当一个键被添加到 sync.Map 时,它被哈希到一个哈希桶中,该桶是一个链表,包含与该哈希值匹配的所有 entry。

如果哈希桶中已经存在一个具有相同键的 entry,则新的 entry 将被添加到链表的末尾。否则,一个新的 entry 将被创建并添加到哈希桶中。

互斥锁

每个 entry 都包含一个互斥锁,用于保护键值对。当一个 goroutine 想访问一个 entry 时,它必须先获取该 entry 的锁。这确保了其他 goroutine 在访问该 entry 之前无法修改它。

插入和获取

当一个键值对被插入到 sync.Map 时,它被哈希到一个哈希桶中。如果哈希桶中已经存在一个具有相同键的 entry,则该 entry 的值将被更新。否则,一个新的 entry 将被创建并添加到哈希桶中。

当一个键从 sync.Map 中获取时,它被哈希到一个哈希桶中。然后,链表被遍历以找到具有给定键的 entry。如果找到一个匹配的 entry,则返回该 entry 的值。否则,返回 nil。

性能

sync.Map 的 entry 结构通过结合哈希表和链表来提供良好的性能。哈希表允许快速查找和插入,而链表允许处理哈希冲突。互斥锁确保并发访问时的线程安全性。

并发安全

sync.Map 中的 entry 机制通过使用互斥锁来确保并发安全。每个 entry 都包含一个互斥锁,用于保护键值对。当一个 goroutine 想访问一个 entry 时,它必须先获取该 entry 的锁。这确保了其他 goroutine 在访问该 entry 之前无法修改它。

总结

sync.Map 中的 entry 数据结构是提升性能和确保并发安全的关键。它通过使用哈希表和链表来提供快速查找和插入,并使用互斥锁来保护键值对,防止并发访问时发生数据竞争。理解 entry 机制的运作方式对于充分利用 sync.Map 至关重要,可以帮助开发人员构建更健壮、更高效的多线程应用程序。