map - 在 Go 中使用范围获取值不是线程安全的吗?

标签 map go

当遍历具有并发写入器的 map m 时,包括可以从 map 中删除的写入器,这样做不是线程安全的吗?:

for k, v := range m { ... }

我正在考虑线程安全我需要防止其他可能的编写者在我读取它时更改值v,并且(当使用互斥锁时并且因为锁定是一个单独的步骤) 验证键 k 仍在 map 中。例如:

for k := range m {
    m.mutex.RLock()
    v, found := m[k]
    m.mutex.RUnlock()
    if found {
        ... // process v
    }
}

(假设其他编写器在更改v 之前写锁定m。)有没有更好的方法?

编辑补充:我知道 map 不是线程安全的。然而,根据位于 http://golang.org/ref/spec#For_statements 的 Go 规范,它们在某种程度上是线程安全的。 (搜索“如果尚未到达的 map 条目在迭代期间被删除”)。此页面表明使用 range 的代码无需担心其他 goroutines 插入或删除 map 。我的问题是,这种线程安全性是否扩展到 v,这样我就可以仅使用 获得 v 只读对于 k, v := range m 而没有其他线程安全机制?我创建了一些测试代码来试图强制应用程序崩溃以证明它不起作用,但即使运行公然线程不安全的代码(许多 goroutine 在没有锁定机制的情况下疯狂地修改相同的映射值)我也做不到去崩溃吧!

最佳答案

不, map 操作不是原子/线程安全的,因为您问题的评论者指出了 the golang FAQ “Why are map operations not defined to be atomic?” .

为了确保您的访问安全,我们鼓励您使用 Go 的 channels作为资源访问 token 的手段。该 channel 用于简单地传递 token 。任何想要修改它的人都会从 channel 请求 - 阻塞或非阻塞。处理完 map 后,它会将 token 传回 channel 。

遍历和使用 map 应该足够简单和简短,因此您应该只使用一个 token 就可以完全访问。

如果不是这种情况,并且您将 map 用于更复杂的内容/资源消费者需要更多时间,您可以实现读者访问 token 与写入访问 token 。因此在任何给定时间,只有一个作者可以访问 map ,但是当没有作者处于事件状态时, token 将传递给任意数量的读者,他们不会修改 map (因此他们可以同时读取)。

有关 channel 的介绍,请参阅 the Effective Go docs on channels .

关于map - 在 Go 中使用范围获取值不是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12938233/

相关文章:

c++ - C++11 映射值的迭代器(简单透明)

scala - 迭代器上的Scala映射不会产生副作用

Go goroutine 泄漏

Golang 浮点运算

Golang 导出类型

Go 语言中指向结构的指针

ios - 缩小和放大后 MapOverlay 闪烁-iOS

scala - Scala对 map 进行多分区-类型不匹配;找到(A,B)=>需要 bool 值(A,B)=> bool 值吗?

c++ - 自定义对象的 STL 集,每个包含一个 STL 集

go - VSCode 是如何发现这个 Go linting 问题的?我该如何忽略它?