@mantyr
Пишу много Golang кода с удовольствием:)

Как удалять из map в цикле если цикл защищён через RWMutex.RLock() в Golang?

Имеем:
1. map который защищён через RWMutex
2. когда читаем данные из map ставим RLock(), потом отпускаем через RUnlock()
3. когда пишем в map ставим Lock, потом отпускаем через Unlock()

Что делать если мы читаем map через цикл и в какой-то момент понимаем что этот элемент нам в map больше не нужен и его можно и нужно удалить? При этом цикл уже защищён через RLock (только на чтение, не на запись).

Варианты:
1. отпустить RLock(), взять Lock()
2. как-то по другому превратить RLock() в Lock()
3. записывать ключи удаляемых элементов в slice и проходить по ним отдельным циклом в конце блокируя map через Lock(). Минус - надо ждать, зато потом пачкой удаляются элементы.
4. сделать go l.delete(key) и вынести в эту функцию удаление с Lock/Unlock? Минусы - может быть взлёт количества горутин равное количеству элементов. При этом если есть конкурентное чтение этого map с таким же go l.delete(key) то умножаем на количество конкурентных потоков которые этот map читают, плюс ещё горсточка накопившаяся за то время пока элемент не успел удалиться.

Пример кода на скорую руку тут: https://play.golang.org/p/5od76B-GVg

Задал аналогичный вопрос в англоязычном https://stackoverflow.com/questions/36754838/is-it... и пишут что delete так же надо защищать через Lock, вот только не понятно как делать удаление эффективно при чтении map в цикле.

Ссылки на исходный код приветствуются, как впрочем и просто мнения.
  • Вопрос задан
  • 1096 просмотров
Пригласить эксперта
Ответы на вопрос 2
bitver
@bitver
Судя по коду вангую вы делаете не то, что вам хочется, это не Worker pool ли обычный? Таких в нэте полно, поищите.
Если вам нужно чтоб работал текущий код, то да, нужно лочить delete тоже в обязательном порядке и лочить RLock() при чтении (не вне цикла, а прям при чтении), если вне цикла - то вариант со слайсом вроде как подойдёт.
Немного поигрался, такой вариант покрасивее, имхо. Но есть одно "но", for range по такому не пройдёшься.
https://play.golang.org/p/CeGHYK5nBr
Ответ написан
@GeckoGreen
4 вариант почти тоже, что и 3, ибо до RUnlock() все рутины будут в спячке, а после этого начнут конкурировать за захват мьютекса. Поэтому третий лучше четвертого будет.
2 вариант получится реализовать только путем реализации своего мьютекса, что не самый лучший вариант. Можно, конечно, использовать 1 вариант, но там свистопляски с мьютексами и поэтому может получиться медленнее не очень эффективно. Возможен 5 вариант. Если удаление будет происходить только в 1 рутине, то можно делать новую мапу, а после скана подменять переменную. Но результат, естественно, будет после окончания цикла.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы