Benchmark: Generics unique vs Unique

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.

benchmark: generics

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.

profile memória: generics

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!


Subscreva

Fique por dentro de tudo o que acontece no mundo Go.

Um comentário sobre “Benchmark: Generics unique vs Unique

Deixe uma resposta