【问题标题】:Concurrency-safe map of slices切片的并发安全映射
【发布时间】:2020-06-23 04:42:53
【问题描述】:

我有一个包含sync.Map 的类型,其中映射中的键是字符串,值是切片。我在地图中插入项目的代码如下:

newList := []*Item{item}
if result, ok := map.LoadOrStore(key, newList); ok {
    resultList := result.([]*Item)
    resultList = append(resultList, item)
    map.Store(key, resultList)
}

这不是并发安全的,因为切片可以通过多个调用同时加载和修改。这段代码非常脆弱,所以我尝试将其修改为:

newList := []*Item{item}
if result, ok := map.LoadOrStore(key, &newList); ok {
    resultList := result.(*[]*Item)
    *resultList = append(*resultList, item)
}

所有这一切都是使问题确定性地发生。所以,我正在尝试找到一种方法来创建一个可以同时添加的切片图。我的直觉是在添加列表时使用sync.Mutex 锁定列表,但为了保持对sync.Map 的并发访问,我还需要创建sync.Mutex 对象的映射,如下所示:

newLock := sync.Mutex{}
raw, _ := lockMap.LoadOrStore(key, &newLock)
lock := raw.(*sync.Mutex)

newList := []*Item{item}
if result, ok := map.LoadOrStore(key, &newList); ok {
    lock.Lock()
    resultList := result.(*[]*Item)
    *resultList = append(*resultList, item)
    lock.Unlock()
}

有没有更简单的方法来解决这个问题?

【问题讨论】:

  • struct { *sync.Mutex, []*Item }的地图怎么样?
  • @phonaputer 这是一个有趣的解决方案。没想到
  • 嗯,这和你现在的想法没什么不同。但是很高兴能够使用嵌入的*sync.Mutex 做类似SafeItems.Lock() 的事情。不用处理两张地图真是太好了。
  • 同意。我实现了它,它解决了我的问题。您想获得此问题的答案吗?
  • 当然我会带你去。

标签: go concurrency


【解决方案1】:

这与您当前的计划并没有太大的不同,但是您可以通过使用带有嵌入式互斥锁的结构来处理两个映射的麻烦来处理映射的值。

结构看起来像这样:

type SafeItems struct {
    sync.Mutex
    Items []*Item
}

它可以这样使用:

newMapEntry := SafeItems{Items: itemPtrList}
if result, ok := map.LoadOrStore(key, &newMapEntry); ok {
    mapEntry := result.(*SafeItems)
    mapEntry.Lock()
    mapEntry.Items = append(mapEntry.Items, item)
    mapEntry.Unlock()
}

这不是一个巨大的变化,但它确实提供了一些语法糖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-10
    • 2015-11-09
    • 2018-08-31
    • 1970-01-01
    • 2013-05-30
    • 2021-07-17
    • 1970-01-01
    • 2021-09-24
    相关资源
    最近更新 更多