【问题标题】:Golang RWMutex on map content edit地图内容编辑上的 Golang RWMutex
【发布时间】:2018-08-04 17:38:22
【问题描述】:

我开始在我的 Go 项目中使用 RWMutexmap,因为现在我有多个例程同时运行,并且在为此进行所有更改时,我想到了一个疑问。

问题是我知道我们必须在仅读取时使用RLock 以允许其他例程执行相同的任务,而在写入全块地图时使用Lock。但是在地图中编辑之前创建的元素时我们应该怎么做呢?

例如...假设我有一个map[int]string,我在其中做Lock,放入"hello ",然后放入Unlock。如果我想添加"world" 怎么办?我应该Lock 还是RLock 可以?

【问题讨论】:

  • 有两种操作,读和写。编辑值是写操作,而不是读操作。

标签: dictionary go mutex


【解决方案1】:

你应该从另一个角度来解决这个问题。

您似乎可以理解的简单经验法则是

当其中至少一个是修改时,您需要保护地图免受并发访问

现在真正的问题是什么构成了地图的修改。

要正确回答这个问题,请注意存储在地图中的值是不可寻址的——这是设计使然。 之所以这样设计,仅仅是因为事实地图内部具有复杂的实现 might move values they contain in memory 提供(摊销的)快速访问时间 当地图的结构由于其元素的插入和/或删除而发生变化时。

事实地图值不可寻址意味着您不能这样做 像

m := make(map[int]string)
m[42] = "hello"
go mutate(&m[42]) // take a single element and go modifying it...
// ...while other parts of the program change _other_ values
m[123] = "blah blah"

您不允许这样做的原因是 插入操作m[123] = ... 可能会触发移动 地图元素的存储,这可能 涉及移动由42 键入的元素的存储 到记忆中的另一个地方——拉地毯 从 goroutine 的脚下 运行mutate 函数。

所以,在 Go 中,地图实际上只支持三种操作:

  • 插入或替换一个元素;
  • 读取一个元素;
  • 删除一个元素。

你不能“就地”修改元素——你只能 分三步走:

  1. 读取元素;
  2. 修改包含(读取)副本的变量;
  3. 用修改后的副本替换元素。

如您现在所见,步骤 (1) 和 (3) 只是地图访问, 所以你的问题的答案(希望)很明显: 步骤(1)应至少在读锁下进行, 并且步骤(3)应在写(独占)锁下完成。


相比之下,其他复合类型的元素—— struct 类型的数组(和切片)和字段 — 没有限制地图有:提供存储 “封闭”变量的未重定位,可以 通过不同的 goroutine 同时改变它的不同元素。

【讨论】:

    【解决方案2】:

    由于在map中改变与key关联的值的唯一方法是将改变后的值重新分配给同一个key,即写/修改,所以你必须获得写锁——只需使用读锁是不够的。

    【讨论】:

      猜你喜欢
      • 2013-03-05
      • 1970-01-01
      • 2021-12-25
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多