Go. Хватит хранить одно и то же

Пусть в памяти есть миллион строк. Уникальных — тысяч десять. Остальное — одни и те же значения, которые ты хранишь снова и снова. В Go для таких случаев есть пакет unique, который многие разработчики почему-то игнорируют.

Он появился в Go 1.23 и решает старую задачу interning: хранить одну каноническую копию одинаковых значений.

words := make([]unique.Handle[string], n) for i := range n {     words[i] = unique.Make(generate()) }

unique.Make() принимает любое comparable-значение и возвращает Handle.

Если сделать так:

go a := unique.Make("postgres") b := unique.Make("postgres")

то:

a == b // true

Почему это полезно?

Мы уже не сравниваем содержимое двух строк. Сравнение Handle сводится к сравнению ссылок на одну каноническую копию.

Получаем сразу две вещи: — не плодим одинаковые значения в памяти; — дешевле сравниваем их между собой.

Под капотом unique хранит канонические значения в конкурентно-безопасном хранилище. Пока существует Handle, значение живёт. Когда все Handle исчезли, запись со временем может забрать GC.

Но unique — не универсальная оптимизация.

Если у тебя 100 000 почти всегда разных строк, пользы будет мало. Ты просто добавишь работу на canonicalization.

А вот если в системе миллионы повторяющихся hostname, region, type, status, zone или других значений из ограниченного набора — уже интереснее.

Много повторов — смотри в сторону unique. Нет повторов — не тащи его в код просто потому, что пакет новый.

Селькин Андрей
TGM / Go-разработчик из Fintech. Инженерные заметки: https://t.me/andrei_selkin_outbox
1