锁定Golang递归映射

5

我有一个递归的类似于地图的结构,它看起来像这样:

type RecurseTable struct {
    Table map[string]*RecurseTable
    // Other fields
    sync.RWMutex
}

如果我要从多个goroutine访问这个结构,我该如何锁定它呢?假设我正在从顶层map中读取并写入第三层嵌套map,那么说改变第三层(因此间接地通过两个指针)不应该影响顶层map,这是准确的吗?
同样,如果我有一个goroutine池,所有goroutine都在修改第二级嵌套结构中的信息,那么我只需要锁定每个第二级map,因为顶层map只包含对嵌套RecurseTable的指针,这是正确的吗?还是说我必须同时锁定顶层map和嵌套结构,因为该结构可能会在内存中重新分配,导致将其作为值存储在顶层map中的指针发生更改?
另一种情况是在读取第二级结构时向顶层map添加键。可以安全地假设由于新键而对顶层map进行的任何重组都不会影响内存中第二级结构的位置,因此在读取时无需锁定该结构吗?
我的目标是将整个递归结构的全局锁最小化,以便我的goroutine可以并行地处理结构的不同部分,最小化锁争用。我想问的核心问题是maps在Golang中如何调整大小。

2
一旦您拥有一个指向深度映射的指针,您就不需要担心顶部的层:对象不会在内存中移动;一旦您拥有一个对象的指针,此指针就是有效的。如果其他某个对象包含相同指针值(这里是映射桶),那么这并不重要。但是,任何写访问都必须通过持有适当级别的锁来保护。为什么不在竞争检测器下运行您的代码呢? - Volker
是的,我试过了,一切都很好 :) - a3onstorm
2个回答

2
Go maps in action博文中可以看出:

Maps不适合并发使用:同时读写它们时未定义结果。如果您需要在并发执行的goroutine中从地图中读取和写入数据,则必须通过某种同步机制来调解访问。保护映射的一种常见方法是使用sync.RWMutex

当您将地图指针提供给其他地图时,您可以独立于其他地图(兄弟或后代)安全地锁定一个地图:即使在使用其子孙时删除地图条目,也不会有问题,因为它们的引用将保持直到您释放指针(即删除它们的变量)。

1
正如他所说,他想要写入地图,这意味着替换该值的指针。因此,虽然没有竞争条件,但问题仍然是,如果访问引用的子映射应该防止在某个上层表中替换指向它的指针。也许它会变得无法访问。这取决于应用程序,因此需要从OP获取更多信息。 - metakeule
嗯,我认为在特定级别上进行锁定就足够了。每个映射只创建一次,从不用新映射替换 -> 条目随时间添加,结构的其他字段也被写入。 - a3onstorm
啊,我明白了 - 那就去做吧。 - metakeule

2

一种方法是不导出 Table 成员,而提供适当加锁的 Get/Set 方法。例如:

type RecurseTable struct {
    table map[string]*RecurseTable
    // Other fields
    sync.RWMutex
}

func New() *RecurseTable {
    return &RecurseTable{
        table: make(map[string]*RecurseTable),
    }
}

func (r *RecurseTable) Get(key string) (*RecurseTable, bool) {
    r.RLock()
    defer r.RUnlock()
    return r.table[key]
}

func (r *RecurseTable) Set(key string, value *RecurseTable) {
    r.Lock()
    defer r.Unlock()
    r.table[key] = value
}  

这样,访问地图数据的唯一方式就是通过保护地图访问的方法。然后每个值都被独立保护。


OP 需要在访问点锁定层次结构中的每个映射,因为这些映射都不是线程安全的。在 OP 的问题中,他可以读取锁定父级并在两个不同的 goroutine 中获取映射值。访问这些值是非线程安全的,需要进行保护。 - Ian Davis
我猜你得编辑你的回答,这样我才能取消我的踩。非常抱歉... - metakeule
谢谢你的回答,这绝对是我通常会采取的方式,因为它保证了安全性。然而,我现在的主要优先事项是效率,所以我认为我会坚持手动锁定,这样我就可以进行连续的读写操作,而不需要锁定和解锁的开销。 - a3onstorm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接