Aproveitando o post do Elton Minetto (Testando o generics do Go), onde ele fez um benchmark comparando uma função escrita sem generics e uma com, nesse post vamos dar continuidade na análise que ele fez fazendo um profile de memória e passando a flag -benchmem.
O código utilizado foi exatamente o mesmo que o Elton utilizou em seus testes.
Se você não viu o post dele, deixo abaixo as duas funções utilizadas. A primeira foi copiada do package samber/lo
utilizando generics, enquanto a segunda foi implementada pelo próprio Elton.
package main import ( "fmt" ) func main() { s := []string{"Samuel", "Marc", "Samuel"} names := Uniq(s) fmt.Println(names) names = UniqGenerics(s) fmt.Println(names) i := []int{1, 20, 20, 10, 1} ids := UniqGenerics(i) fmt.Println(ids) } //from https://github.com/samber/lo/blob/master/slice.go func UniqGenerics[T comparable](collection []T) []T { result := make([]T, 0, len(collection)) seen := make(map[T]struct{}, len(collection)) for _, item := range collection { if _, ok := seen[item]; ok { continue } seen[item] = struct{}{} result = append(result, item) } return result } func Uniq(collection []string) []string { result := make([]string, 0, len(collection)) seen := make(map[string]struct{}, len(collection)) for _, item := range collection { if _, ok := seen[item]; ok { continue } seen[item] = struct{}{} result = append(result, item) } return result }
E para o benchmark, foram feitas 3 funções bem simples.
package main import ( "testing" "github.com/bxcodec/faker/v3" ) var names []string func BenchmarkMain(m *testing.B) { for i := 0; i < 1000; i++ { names = append(names, faker.FirstName()) } } func BenchmarkNormalUniq(b *testing.B) { _ = Uniq(names) } func BenchmarkGenericsUniq(b *testing.B) { _ = UniqGenerics(names) }
Ao executar o go test -bench=. -cpu 8 -benchtime 100x -memprofile mem.prof -benchmem
podemos ver que tive um resultado muito similar ao dele.

Três coisas me agradaram muito nesse benchmark. Em primeiro lugar, a diferença de nano segundos por operação (ns/op) não é muito grande. Já em segundo e terceiro lugar, ambas funções consumiram a mesma quantidade de bytes por operação (B/op) e fizeram a mesma quantidade de alocações por operação (allocs/op).
Isso mostra que em tempo de execução, quando falamos de consumo de recurso, uma função com generics consome exatamente a mesma coisa que qualquer função “comum”.
Para fechar, vamos dar uma conferida em como ficou o profile de memória.

E vejam só que coisa mais linda! Ao serem executadas, ambas funções consumiram exatamente a mesma quantidade de memória, ou seja… VEM GENERICS!!!!!!
Deixem suas dúvidas nos comentário.
Até a próxima!
[…] Benchmark: Generics unique vs Unique […]