Ответ
Механизм эвакуации (evacuation) в Go — это процесс постепенного переноса данных из старой хэш-таблицы в новую, увеличенную, когда map
становится слишком заполненной.
Когда это происходит?
Эвакуация начинается, когда коэффициент загрузки (load factor) карты превышает 6.5
. Это означает, что в среднем на одну корзину (bucket) приходится более 6.5 элементов.
Как это работает?
- Создание новой таблицы: Go выделяет память под новую хэш-таблицу, которая обычно в два раза больше старой.
- Постепенный перенос: Вместо того чтобы остановить все операции и скопировать все данные сразу (что вызвало бы заметную задержку), Go переносит данные инкрементально. При каждой операции записи или удаления в
map
эвакуируются (переносятся) одна или две старые корзины. - Двойное чтение: Во время эвакуации, если ключ не найден в новой таблице, Go ищет его в старой. Это гарантирует, что все данные остаются доступными в течение всего процесса.
Зачем это нужно?
Основная цель — избежать больших пауз (stop-the-world) при изменении размера map
. Постепенная эвакуация "размазывает" затраты на перераспределение по множеству мелких операций, что критически важно для систем с низкими задержками (low-latency).
Пример, который инициирует эвакуацию:
package main
import "fmt"
func main() {
// Создаем карту с начальной емкостью 8 корзин (buckets)
m := make(map[int]string)
// Добавляем большое количество элементов
// По мере заполнения карты коэффициент загрузки будет расти,
// и Go запустит механизм эвакуации для её расширения.
for i := 0; i < 1000; i++ {
m[i] = fmt.Sprintf("value_%d", i)
}
fmt.Println("Map populated, evacuation occurred.")
}