Как использовать RWMutex при одновременном изменении карты во время итерации по ней - PullRequest
0 голосов
/ 10 июля 2020

Я хочу использовать ключи карты, чтобы запросить что-то из 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()

1 Ответ

0 голосов
/ 11 июля 2020

То, что вы делаете, должно работать. Однако обратите внимание, что между runlock и rlock все, что вы делаете, - это создаете горутину, поэтому у вас будет много горутин, ожидающих блокировки. Сначала выполняется итерация карты, а затем вносятся изменения, которые легче читать и отлаживать. Или вы можете изменить карту и иметь map[keytype]struct{value *valuetype}, и тогда вам не нужно блокировать карту и запускать свои горутины без мьютексов. Каждая горутина будет изменять map [k] .value вместо map [k].

...