锁定golang递归映射

锁定golang递归映射,go,locking,goroutine,Go,Locking,Goroutine,我有一个类似于递归映射的结构,如下所示: type RecurseTable struct { Table map[string]*RecurseTable // Other fields sync.RWMutex } 如果我要从多个goroutine访问这个结构,我该如何锁定它呢?假设我从顶层映射读取数据,然后写入第三层嵌套映射。因为更改第三级(因此通过两个指针间接定向)不应影响顶级贴图,所以这样说不会导致任何问题,这准确吗 类似地,如果我在第二级嵌套结构中有一个go

我有一个类似于递归映射的结构,如下所示:

type RecurseTable struct {
    Table map[string]*RecurseTable
    // Other fields
    sync.RWMutex
}
如果我要从多个goroutine访问这个结构,我该如何锁定它呢?假设我从顶层映射读取数据,然后写入第三层嵌套映射。因为更改第三级(因此通过两个指针间接定向)不应影响顶级贴图,所以这样说不会导致任何问题,这准确吗

类似地,如果我在第二级嵌套结构中有一个goroutine池,所有修改信息,那么我是否只需要锁定每个第二级映射,因为顶级映射只包含一个指向嵌套递归表的指针?或者,我必须同时锁定顶级映射和嵌套结构,因为该结构可能会以某种方式重新分配到内存中,从而导致更改作为顶级映射中的值存储的指针

另一种情况是在从第二级结构读取时向顶级映射添加键。可以安全地假定,由于新密钥而对顶级映射进行的任何重新组织都不会影响内存中第二级结构的位置,因此在读取时不必锁定该结构吗

我的目标是最小化整个递归结构的全局锁,这样我的goroutine就可以在结构的不同部分并行工作,而锁争用最少。我想我的问题的核心是关于Golang中的地图如何调整大小。

来自博客:

地图对于并发使用是不安全的:它没有定义当您同时读写地图时会发生什么。如果您需要从并发执行的goroutine中读取和写入映射,那么访问必须通过某种同步机制进行调解。保护地图的一种常见方法是使用
sync.RWMutex


当您将映射指针提供给其他映射时,您可以独立于其他映射(同级或子级)安全地锁定映射:即使您在使用映射项的子级时删除了映射项,也不会有问题,因为它们的引用将被保留,直到您释放指针(即保存它们的变量被删除).

一种方法是不导出表成员,而是提供适当锁定的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需要在访问点锁定层次结构中的每个映射,因为没有一个映射是线程安全的。在OP的问题中,他可以读取锁定父项并在两个不同的goroutine中获取map值。访问这些值不是线程安全的,它们需要加以保护。我想您必须编辑您的答案,以便我能够撤消我的否决票。我很抱歉…谢谢你的回答,这肯定是我通常的做法,因为它保证了安全。然而,我现在的首要任务是提高效率,所以我想我会坚持手动锁定,这样我就可以连续读/写,而不需要锁定和解锁的开销。