Perfilamento de código Go: encontrando gargalos na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que o perfilamento Go é essencial para o desenvolvedor

\n

Go é conhecido por seu desempenho, mas até o código mais rápido pode ficar lento devido a algoritmos ineficientes, vazamentos de memória ou mau uso de goroutines. O perfilamento é a única maneira de saber exatamente onde seu aplicativo está gastando recursos. Neste artigo, abordaremos métodos práticos de perfilamento de código Go usando ferramentas integradas: pprof, trace e benchstat. Você aprenderá a encontrar gargalos e eliminá-los.

\n\n

1. Perfilamento de CPU com pprof: encontrando pontos críticos

\n

O perfilamento de CPU mostra quais funções consomem mais tempo de processamento. O pacote integrado runtime/pprof permite coletar perfis facilmente.

\n\n

1.1. Adicionando perfilamento ao código

\n

Vamos considerar um exemplo de um servidor HTTP simples que executa tarefas pesadas:

\n
package main\n\nimport (\n    "fmt"\n    "log"\n    "net/http"\n    _ "net/http/pprof"\n    "os"\n    "runtime/pprof"\n)\n\nfunc heavyTask() {\n    sum := 0\n    for i := 0; i < 1_000_000; i++ {\n        sum += i * i\n    }\n    _ = sum\n}\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    heavyTask()\n    fmt.Fprintf(w, "Done")\n}\n\nfunc main() {\n    f, _ := os.Create("cpu.prof")\n    pprof.StartCPUProfile(f)\n    defer pprof.StopCPUProfile()\n\n    http.HandleFunc("/", handler)\n    log.Fatal(http.ListenAndServe(":8080", nil))\n}\n
\n

Após iniciar o servidor e fazer algumas requisições, você terá o arquivo cpu.prof. Analise-o com o comando:

\n
go tool pprof -http=:8081 cpu.prof
\n

Um gráfico interativo será aberto no navegador. Observe os nós vermelhos — eles indicam as funções mais "quentes". No nosso caso, é heavyTask.

\n\n

1.2. Interpretando os resultados

\n

Na interface web do pprof, você verá:

\n
    \n
  • Graph — grafo de chamadas com tamanhos de nós proporcionais ao tempo de execução.
  • \n
  • Flame Graph — gráfico "chama", onde barras longas representam as seções mais lentas.
  • \n
  • Top — tabela de funções ordenadas por tempo de CPU.
  • \n
\n

Se você perceber que heavyTask está ocupando 90% do tempo, significa que é necessário otimizá-la (por exemplo, substituir o loop por uma fórmula de soma de quadrados).

\n\n

2. Perfilamento de memória: encontrando vazamentos e alocações

\n

Vazamentos de memória em Go são raros, mas alocações excessivas podem desacelerar muito o aplicativo. Usamos runtime/pprof para o perfil de heap.

\n\n

2.1. Coletando o perfil de heap

\n

Vamos adicionar ao código a coleta do perfil de memória via sinal SIGUSR1:

\n
import (\n    "os"\n    "os/signal"\n    "runtime/pprof"\n    "syscall"\n)\n\nfunc main() {\n    // ... seu código ...\n    sigs := make(chan os.Signal, 1)\n    signal.Notify(sigs, syscall.SIGUSR1)\n    go func() {\n        <-sigs\n        f, _ := os.Create("mem.prof")\n        pprof.WriteHeapProfile(f)\n        f.Close()\n        os.Exit(0)\n    }()\n    // ...\n}\n
\n

Após enviar o sinal kill -SIGUSR1 <PID>, você obterá o arquivo mem.prof. Analise:

\n
go tool pprof -http=:8082 mem.prof
\n\n

2.2. Problemas típicos de memória

\n
    \n
  • Grande quantidade de pequenas alocações — por exemplo, criar strings com + em vez de strings.Builder.
  • \n
  • Manter referências a objetos grandes — após o uso, é necessário zerar os ponteiros.
  • \n
  • Goroutines que não terminam — cada goroutine consome pelo menos 4 KB de pilha.
  • \n
\n

Exemplo de código não otimizado:

\n
func badConcat(n int) string {\n    s := ""\n    for i := 0; i < n; i++ {\n        s += "x"  // cada iteração cria uma nova string\n    }\n    return s\n}\n
\n

Otimiz

Blogs

Book Recommendations