如何在golang中实现线程安全的地图?



我正在研究一个多线程模块,需要在golang -map[outer]map[inner]*some_struct中实现地图。外部键(map[outer])将被多个线程(goroutine)访问,以向内部映射添加键。我有一个疑问,如果多个线程可以并发地添加键到内部映射,为一个共同的外键映射[外]。它是线程安全的,是同步的。有更好的选择吗?此外,外键- map[outer]和外键总数在运行时是已知的,因此不能预先定义锁。

为了更好地理解问题陈述,我们可以以添加不同城市的信息为例。我们可以按州划分城市。每个线程代表一个城市。要添加关于城市的信息,第一个线程需要检查外部键状态,(map[state]),然后每个线程将简单地添加信息到map[state][city] = &some_struct{x:y,y:z}

我读了几篇文章,发现了同步。Map适用于并发映射操作,这些操作是自动执行的。但是在文档中提到的一个用例是-,当多个程序读取、写入和覆盖不相交的键集的条目时.

如果有人能建议一个线程安全的方法来解决这个问题,那将会很有帮助。

你必须用面向对象的方式思考

你想用map的map表示什么?

地图状态,城市有一些意义。但是你想做什么样的手术呢?

写和读并发?为什么?

要遍历所有城市吗?你需要删除城市/州吗?

想象下面的接口

type DB interface {
Exists(state, city string) bool
Get(state, city string) *some_struct
Set(state, city string, data *some_struct)
Delete(state, city string)
DeleteState(state string)
ForeachCitiesInState(state string, func(city string, data *some_struct) bool)
Foreach(func(state, city…))
}
对于这个接口,我们可以考虑:

  1. 使用带有互斥锁和map的map的结构体来控制每次读/写/删除的访问
  2. 与1相同,但如果读多于写,则使用读写互斥
  3. 如果你不需要在特定州的城市上循环,也许你可以创建一个映射[复合键]结构,如state:city到简化。
  4. 如果您将以恒定的时间间隔从另一个地方加载它,也许您应该使用atomic。值来存储大的地图。更新只是替换最新的地图。
  5. 也许你可以组合几个rw锁。例如,一个代表州,另一个代表城市。你可以分割成
type states struct {
sync.Mutex
map[ stateName ]state
}
type state struct {
sync.Mutex
map[ cityFirstLetter ]cities
}
type cities struct {
sync.Mutex
map[ cityName ] *some_struct
}

的想法:

  1. 定义接口
  2. 定义(或测量)实际使用场景
  3. <
  4. 写基准/gh>
  5. 返回指向数据的指针要小心。你可以改变内部状态。考虑返回一个副本或一个接口