Имеет ли смысл проверять наличие элемента в мапе перед добавлением с точки зрения производительности в Go
Что проверяют
Понимаете ли вы, что происходит внутри m[k] = v, и умеете ли отделять семантику от производительности. Следом обычно спрашивают про конкурентный доступ: как сделать «вставить, если нет» из нескольких горутин.
Как отвечать
По скорости проверка не помогает, а мешает. m[k] = v в рантайме это один вызов mapassign: он хэширует ключ, находит слот и либо перезаписывает значение, либо вставляет новое. Связка if _, ok := m[k]; !ok { m[k] = v } ищет дважды: сначала mapaccess, потом тот же mapassign. Асимптотика та же, O(1) в среднем, но хэш считается два раза. Переход мап на Swiss Tables в Go 1.24 этого не изменил.
Проверка оправдана, когда меняется поведение:
- не перезаписывать: нужно сохранить первое значение, например первый увиденный timestamp;
- дорогое значение: создавать объект только при отсутствии ключа, иначе конструктор работает впустую;
- разная логика: отличить «ключа нет» от нулевого значения через
v, ok := m[k].
Лишняя проверка: m[k]++ и m[k] = append(m[k], x) работают без неё, отсутствующий ключ отдаёт нулевое значение, а delete по несуществующему ключу ничего не делает.
Обычная мапа не потокобезопасна, при гонке рантайм падает с fatal error: concurrent map writes. Проверка и запись делаются под одним sync.Mutex. Для кэша с частым чтением подходит sync.Map с LoadOrStore или RWMutex с двойной проверкой: под RLock, потом под Lock ещё раз.
Если важна скорость, задайте размер заранее через make(map[K]V, n): рост мапы дороже любой лишней проверки. Спорные случаи решает бенчмарк.
Где спотыкаются
Говорят, что проверка «экономит перезапись». Записать значение в найденный слот почти ничего не стоит, дорогим был поиск, и его удвоили.
Проверяют под RLock, отпускают блокировку и пишут под Lock без повторной проверки. Между блокировками другая горутина успевает вставить ключ, и значение перезаписывается.
Путают отсутствие ключа с нулевым значением: if m[k] == 0 не отличает ключ со значением 0 от отсутствующего, нужна форма с ok.