gpt4 book ai didi

go - 初始化 map 元素,其中值是具有互斥锁 golang 的结构

转载 作者:数据小太阳 更新时间:2023-10-29 03:12:34 26 4
gpt4 key购买 nike

我有一个映射,其中每个值都是指向另一个本身有锁的结构的指针。

type StatMap map[string]*Stats

type Stats struct {
sync.RWMutex
someStats, someMoreStats float64
}

我已经实现了一种方法,我将 StatMap 打包到另一个结构中并为整个 map 设置互斥锁,但我希望从数百个 goroutines 中同时修改 map 中的每个条目,因此它会更有效锁定映射中的每个元素,以便两个或多个 goroutine 可以并行读取和修改条目的值。

我想知道的是,每当出现新 key 时,我如何才能在 map 中初始化一个新条目?如果条目不在 map 中,我无法锁定该条目,并且我无法检查它是否在 map 中(据我所知)以防另一个 goroutine 当前正在修改该条目。

我不知道运行前映射中的键是什么。

我当前的实现(导致数据竞争):

initializeStatMap("key")
statMap["key"].Lock()
// . . .


func initializeStatMap(key string) {
if statMap[key] != nil {
return
}
statMap[key] = &Stats{someStats: 0, someMoreStats: 0}
}

最佳答案

Go 的 map 语义如下:

  • map 存储(不是变量),这就是为什么这些值是不可寻址,这就是为什么你不能做类似的事情

    type T struct {
    X int
    }
    m := make(map[int]T)
    m[0] = T{}
    m[0].x = 42 // won't compile
  • 这个需求主要来自 map ,一个复杂的动态数据结构,应该允许其特定的物理移动它包含的值的实现围绕在内存中——在进行重新平衡等操作时。

这就是为什么 map 只支持添加三个操作(或替换)其元素,取回并删除它们。

map 对于并发使用是不安全的,所以为了做这三个中的任何一个同时在同一张 map 上操作,你需要保护它一种或另一种方式。

因此,一旦您从 map 中读取了一个值,编排并发访问完全是另一回事,在这里,我们面临着另一个关于 map 语义的事实:因为它保留值并且可以在内存中自由复制它们,不允许在 map 上保留任何您想拥有的东西引用语义。例如,保留值是不正确的您的 Stats 直接在 map 中输入——因为它们嵌入了实例sync.Mutex,首次使用后禁止复制。在这里,您已经通过存储指向您的指针来做正确的事情变量。

现在你可以看到这样滚动是很OK的:

  1. 访问映射本身以获取绑定(bind)到并发安全中的键的值方式(例如,通过持有锁)。
  2. 锁定该变量的互斥量并对其进行操作。那不完全涉及 map 。

唯一剩下的可能问题如下。假设您使用锁来保护对 map 的访问。所以你捕获锁,获取绑定(bind)到键的值,通过复制它到一个变量,释放锁并使用值(value)。

现在,当您使用该值的副本时,另一个goroutine 可以通过删除值或替换值来自由更新映射。

虽然在您的情况下技术上没问题 — 因为您的 map 运行于指向变量的指针,并且可以复制指针——从程序语义的角度来看,这可能是不合适的,这是你必须考虑清楚的事情。为了更清楚,一旦您获得了指向 Stats 的某个实例的指针并锁定它,可以从 map 中删除指向此实例的指针,或者保存它的 map 条目可以由另一个指针更新——指向 Stats 的另一个实例,所以一旦你完成了例如,它可能无法通过 map 到达。

关于go - 初始化 map 元素,其中值是具有互斥锁 golang 的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47433579/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com