【问题标题】:Map concurrent usage [closed]映射并发使用[关闭]
【发布时间】:2020-10-05 16:00:25
【问题描述】:

我遇到了这段代码,想知道这是否需要一个 R/W Mutex。

method(){
var (
    wg           sync.WaitGroup
    rwm          sync.RWMutex
    vcnRegionMap map[string][]core.Vcn
)

vcnRegionMap = make(map[string][]core.Vcn)

// This loops helps us in filtering unused regions
// for composition of region/vcnid ds
for _, regionName := range regions {

    wg.Add(1)
    go func(ctx context.Context, region string, vcnRegionMap map[string][]core.Vcn, wg *sync.WaitGroup, rwm *sync.RWMutex) {
        // for locking maps

        defer wg.Done()
        // TODO: make this conditional if a region is specified
        c.network.SetRegion(region)

        vcnResponse, err := c.network.ListVcns(ctx, core.ListVcnsRequest{
            CompartmentId: &c.cID,
        })
        if err != nil {
            logger.Debug(err.Error())
        }
        if len(vcnResponse.Items) == 0 {
            logger.Info("status 404: No Vcns found under the given OCID and region: %s", region)
            return
        }
        
        logger.Info("status 200: Vcns found under the given OCID and region: %s", region)
        for _, item := range vcnResponse.Items {
            logger.Debug("Vcn object: %s", *item.DisplayName)
            // maps are not concurrency safe
            rwm.Lock()
            defer rwm.Unlock()
            vcnRegionMap[region] = append(vcnRegionMap[region], item)
        }

    }(ctx, regionName, vcnRegionMap, &wg, &rwm)
}
wg.Wait()
}

由于每个 goroutine 都有自己的 map 副本,Mutex 是否有帮助,我们可以避免它以减少延迟吗?

【问题讨论】:

  • 我看不到任何地方正在复制 vcnRegionMap 地图。您必须始终同步任何值的并发修改。
  • 将地图头的副本传递给函数,而不是地图的深层副本。每个 goroutine 仍在修改相同的底层映射。
  • Go 中的地图和切片一样,实际上是引用类型。
  • @f-z-N:如果是为了您自己的理解,那么投票无关紧要。它最终可能会被否决,因为如此频繁地重复有关该主题的答案对整个网站来说并不是那么有用。
  • @f-z-N,无论哪种方式都可以。就我个人而言,我会删除参数以消除混淆,因为 4 个参数中有 3 个被有效地关闭了。但是,您必须确保仍然复制 regionName,我会使用 regionName := regionName 成语。

标签: go go-map


【解决方案1】:

您需要保护地图不被同时访问。代码错误,因为您正在读取锁定互斥锁,但正在写入映射。

 for _, item := range vcnResponse.Items {
            logger.Debug("Vcn object: %s", *item.DisplayName)
            // maps are not concurrency safe
            rwm.Lock()
            vcnRegionMap[region] = append(vcnRegionMap[region], item)
            rwm.Unlock()
        }

请注意,此版本不使用defer。延迟操作在函数返回时运行,而不是在块结束时运行。您读取锁定互斥锁n 次,每次迭代一次,然后在函数返回时释放所有这些。

【讨论】:

  • @JimB,真的可以吗?它仍然是对地图的写入。你不会破坏地图,但如果没有锁,它会很有趣。
  • 是的,你是对的,从技术上讲,它是一个写入,即使密钥是相同的。问题根本与切片无关,但也有一场可能值得一提的比赛。
猜你喜欢
  • 2019-10-31
  • 2019-09-11
  • 1970-01-01
  • 1970-01-01
  • 2012-03-05
  • 2012-12-11
  • 1970-01-01
  • 2021-08-30
  • 2022-01-23
相关资源
最近更新 更多