В Go 1.23 добавили новый пакет unique
для “interning”. Interning - это процесс хранения в памяти только одной копии значения и совместного использования уникальной ссылки на нее вместо аллокации нескольких копий и траты памяти.
Подробней можно посмотреть в Реализация interning в Go
Interning позволяет:
- уменьшить потребление памяти
- не тратить время на лишние аллокации и освобождение памяти
- увеличить скорость сравнения объектов
Посмотрим насколько эффективней может стать сравнение строк
Будем сравнивать две строки разных размеров.
Small - строки увеличены в 10 раз, Medium - в 100 и Large - в 1000000.
StringCompare - обычное сравнение двух строк, Canonicalising - использует unique
.
package main
import (
"strings"
"testing"
"unique"
)
func BenchmarkStringCompareSmall(b *testing.B) { benchStringComparison(b, 10) }
func BenchmarkStringCompareMedium(b *testing.B) { benchStringComparison(b, 100) }
func BenchmarkStringCompareLarge(b *testing.B) { benchStringComparison(b, 1000000) }
func BenchmarkCanonicalisingSmall(b *testing.B) { benchCanonicalising(b, 10) }
func BenchmarkCanonicalisingMedium(b *testing.B) { benchCanonicalising(b, 100) }
func BenchmarkCanonicalisingLarge(b *testing.B) { benchCanonicalising(b, 1000000) }
func benchStringComparison(b *testing.B, count int) {
s1 := strings.Repeat("2001:0db8:0001:0000:0000:0ab9:C0A8:0102,", count)
s2 := strings.Repeat("2001:0db8:0001:0000:0000:0ab9:C0A8:0102,", count)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if s1 != s2 {
b.Fatal()
}
}
b.ReportAllocs()
}
func benchCanonicalising(b *testing.B, count int) {
s1 := unique.Make(strings.Repeat("2001:0db8:0001:0000:0000:0ab9:C0A8:0102,", count))
s2 := unique.Make(strings.Repeat("2001:0db8:0001:0000:0000:0ab9:C0A8:0102,", count))
b.ResetTimer()
for n := 0; n < b.N; n++ {
if s1 != s2 {
b.Fatal()
}
}
b.ReportAllocs()
}
Получаем такие результаты:
$ go test -run='^$' -bench=.
goos: darwin
goarch: arm64
pkg: github.com/germangorelkin/sandbox/golang/interning
cpu: Apple M3 Pro
BenchmarkStringCompareSmall-12 182713568 6.398 ns/op
BenchmarkStringCompareMedium-12 24486400 50.74 ns/op
BenchmarkStringCompareLarge-12 1594 707434 ns/op
BenchmarkCanonicalisingSmall-12 1000000000 0.2558 ns/op
BenchmarkCanonicalisingMedium-12 1000000000 0.2576 ns/op
BenchmarkCanonicalisingLarge-12 1000000000 0.2497 ns/op
PASS
ok github.com/germangorelkin/sandbox/golang/interning 5.354s
Скорость(ns/op) сравнения у обычных строк растет отностительно их длины, а сравнения канонизированых остается неизменно низкой, независимо от того, выполняется ли сравнение над строкой длиной 10 копий или 1 000 000.
Источники
Комментарии в Telegram-группе!