【问题标题】:What is the danger of neglecting goroutine/thread-safety when using a map in Go?在 Go 中使用 map 时忽略 goroutine/thread-safety 的危险是什么?
【发布时间】:2016-02-16 11:17:04
【问题描述】:

Go 的 map 据说不是 goroutine-safe(参见 herehere)。我有兴趣了解在我忽略使用互斥锁/等保护对地图的访问的情况下会发生什么。

具体来说,是否会发生以下任何情况?

  1. 假设我有一个带有键 k1k2、...、kn 的地图,当我要求 map[kj] (i != j) 时,并发问题会导致得到 map[ki] 吗?
  2. 它会导致应用程序中的panic 吗?

【问题讨论】:

  • 你会破坏内存。在 go 1.6 中,当检测到这种情况时,它会故意使程序崩溃以防止不安全的行为。一个 map 不能安全地并发使用并不重要,没有任何值可以安全地在 go 中并发读写。
  • 确实没有必要知道您的具体问题的答案。你的代码坏了。破碎,不是“破碎但以这种特定方式破碎,在这种情况下是可以的”。刚刚坏了。
  • @JimB 谢谢。不用说,我知道这一点,否则我不会链接到上述来源。我实际上已经写了这个 repo 来处理它:github.com/streamrail/concurrent-map 但是我从来没有能够证明这个问题,这就是我问上面的原因。任何可以回答我的问题的代码参考将不胜感激。
  • 即使你找到了问题的答案,这些答案可能在下一个 Go 版本中或在另一个平台上,或者在使用不同的编译器时已经过时了......这几乎可以呈现信息没用...也可能重复thisthis
  • 唯一普遍的答案是,就像任何竞争条件一样,任何事情都可能发生。尤其是使用地图,一旦它损坏,您就可以从程序内存中的任何位置进行读写。每当有人遇到“奇怪的运行时错误”时,它几乎总是一场数据竞赛。

标签: multithreading go thread-safety


【解决方案1】:

正如 cmets 已经说过的,比赛很糟糕。与 Java 不同,Go 的保证非常弱,因此具有任何竞态的程序被允许具有未定义的行为即使包含竞态的代码没有被执行。在 C 中,这被称为“catch-fire 语义”。比赛的存在意味着任何结果都是可能的,包括你的电脑着火了。

但是,在 Go 中,很容易使地图线程安全。考虑以下几点:

// Global variable defining a map
var safemap = struct {
    sync.RWMutex
    m map[string]string
}{m: make(map[string]string)}

您可以像这样从地图中进行安全读取:

// Get a read lock, then read from the map
safemap.RLock()
defer safemap.RUnlock()
return safemap.m[mykey] == myval

您可以像这样进行安全修改:

// Delete from the map
safemap.Lock()
delete(safemap.m, mykey)
safemap.Unlock()

或者这个:

// Insert into the map
safemap.Lock()
safemap.m[mykey] = myval
safemap.Unlock()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2012-01-13
    • 2017-11-16
    • 2011-07-17
    • 1970-01-01
    相关资源
    最近更新 更多