【发布时间】:2020-10-31 15:51:56
【问题描述】:
我想使用地图的键向 API 请求某些内容,然后根据 API 的响应更新相应的值。
我的猜测是下面的代码。
或者也许从头开始这种方法,在迭代之前将映射键收集到一个数组中 然后使用数组条目发出请求并修改地图
wg := &sync.WaitGroup{}
wg.Add(len(someMap))
sem := semaphore.NewWeighted(maxWorkers)
ctx := context.TODO()
mutex := &sync.RWMutex{}
mutex.RLock()
for k, v := range someMap {
mutex.RUnlock()
go func(k, v) {
defer wg.Done()
sem.Acquire(ctx, 1)
res, err := API.REQUEST(k)
sem.Release(1)
if err != nil {
return
}
v.SomeElement = res.SomeElement
mutex.Lock()
someMap[k] = v
mutex.Unlock()
}(k, v)
mutex.RLock()
}
mutex.RUnlock()
wg.Wait()
【问题讨论】:
-
虽然 IIRC 您可以成功锁定范围子句,但这里的问题是您最终可能会或可能不会遍历新键。来自规范:
If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped。我只会收集你想要迭代的键,让代码更容易理解 -
感谢您的回答!使用额外的数组可以大大简化代码(这在 IMO 中更可取)。但我有点不喜欢分配不必要的内存的想法。即使它甚至可以加速代码,因为它会摆脱所有那些 RLock 操作,地图也不是真的“大”。并且不会创建任何条目,因为我只想更新现有条目。
-
好吧,如果地图不是那么大,那么分配一个键的切片并不是什么大问题。通过网络执行单个 API 调用可能会分配更多数量级。谨防在没有实际数据的情况下进行优化。
标签: loops go concurrency mutex go-map