【问题标题】:Concurrent writes into Map containing another Map in Golang并发写入包含 Golang 中另一个 Map 的 Map
【发布时间】:2017-10-05 04:41:36
【问题描述】:

在 Golang 中,我们必须将并发更改同步到 Map。如果我的地图包含另一个这样的地图:

map[string]map[string]*CustomStruct

.. 写东西时我必须在所有这些中都使用 Lock 吗?

如果我在内部 Map 中写入一些东西 -> 外部 Map 也会被更改,所以我仍然需要同步外部 Map 的更改。

如果我锁定外部 Map 的更改 -> 没有其他人可以写入内部 Map -> 没有必要锁定内部 Map。

我是对的还是它以不同的方式工作,我必须锁定所有地图?

【问题讨论】:

  • 只需在竞争检测器下尝试一下 :-) 如果您可以确保没有两个代码路径同时写入同一个内部映射,那么您应该很好。但是为什么要冒险呢?这里的一个可爱的小互斥锁有什么问题,或者可能有几个?
  • @Volker,我可以加几个锁,但我觉得没用的锁/解锁就像未使用的变量-为什么它存在?!

标签: go concurrency


【解决方案1】:

我的理解是这里没有任何硬性规定。

例如,您可以通过一个甚至未存储在地图上的互斥锁来协调所有映射写入,任何互斥锁与您的映射之间没有固有的链接 - 它只是关于您如何使用它们来协调对数据的访问。

基本上,如果您锁定单个元素,您将看到较少的锁争用,因为锁的获取频率较低,如果您在所有映射上使用外部锁,则会出现更多争用,因为更多进程将尝试获取相同的锁锁定,这将减少您的流程可以完成的实际工作量。

最终由您来确定最适合您的用例的方法

帮助:

go 1.9 中提供了一个新工具,可让您对锁争用进行基准测试,以了解哪种方法对您的应用程序最有效。

使用-race 标志构建和运行您的应用程序将有助于确定锁是否正常工作

你也可以看看我还没有玩过的新同步地图,但我知道会为你处理这个:

Sync maps

【讨论】:

  • 但是改变内部地图也会改变外部地图 - 这是真的吗?因为总的来说它是一张大地图。所以我总是不得不锁定外部地图
  • 简短的回答是这取决于您是否需要(外部地图可以更改吗?) - 如果外部地图将始终引用相同的内部地图,那么您不需要,如果您只添加新的内部映射,那么您可以获得一个读锁(您可以获得多个读锁)。如果有可能另一个进程会从外部映射中删除内部映射,或者用不同的映射替换它,那么是的,你这样做
  • 将外部映射视为指向内部映射(它们是)的指针映射可能会有所帮助,只要指针不改变你就很好
  • 我的外部地图总是可以更改的,新条目出现并且可能被修改,其他一些消失。因此,如果我添加新的内部地图 - 我应该锁定外部地图;如果我修改内部地图 - 我应该只锁定这个内部地图;如果我删除内部地图 - 外部地图应该被锁定?!对吗?
  • 不幸的是,如果有机会从外部地图中删除地图,我认为您在修改内部地图时总是需要在外部地图上获取写锁,否则它可能会被删除在修改过程中。因此,出于您的目的,您最好取消内部地图上的锁定,并在每次修改任何内容时锁定外部地图。如果性能是一个问题,您可能会考虑将更改批处理或将内部映射嵌套在结构中的某种方式。然后,您可以在修改或删除内部地图时锁定此结构并定期清理它们。
【解决方案2】:

简单(而且很可能已经足够好)的解决方案是拥有一个保护整个结构的互斥锁。它可以是常规互斥锁或读写互斥锁,以防读取比写入频繁得多。这很容易实现,也很容易推理,并且在绝大多数情况下都能胜任。

另一方面,如果您正在寻找挑战,那么您可以从多个方向着手:

  • 每个顶级映射键有一个顶级读写互斥锁和一个(简单或读写)互斥锁。向顶级映射添加或删除条目时写锁定顶级互斥锁;否则读取锁定它,获取特定于条目的锁并读取或写入条目(这也是一个映射)。
  • 决定您想要什么样的并行性,并将您的顶级映射拆分为分片,键根据其哈希值进行分片,每个分片一个互斥体。然后,您可以对多个键进行并行写入(键添加和删除),只要它们位于不同的分片中。
  • 也将第二种方法应用于二级地图。疯了! :o)

但是,说真的,除非这张地图很大,否则您的大部分应用程序只是在其中添加和删除内容,并且您愿意投入大量精力来进行基准测试和调整您的实现,请选择单一的锁定方法。在一般情况下,它实际上会快得多,而且作为奖励,它很容易实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-03
    • 2014-10-01
    • 1970-01-01
    • 2015-11-06
    • 1970-01-01
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多