Perfilamento de código Go: encontrando gargalos para iniciantes

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

Perfilamento de código Go: encontrando gargalos para iniciantes

\n\n

Quando seu projeto Go começa a ficar lento, consumir muita memória ou funcionar de forma instável, surge uma pergunta natural: "Onde está o gargalo?" Palpites intuitivos raramente ajudam — são necessários dados precisos. Perfilamento (profiling) é o processo de coletar métricas sobre o funcionamento do programa: quanto tempo cada função leva, quanta memória é alocada, com que frequência o coletor de lixo é chamado. Neste artigo, vamos explorar como usar as ferramentas integradas do Go (pprof e trace) para encontrar e corrigir rapidamente problemas de desempenho.

\n\n

O que é perfilamento e por que ele é necessário?

\n\n

Perfilamento é como um raio-X para o seu código. Você não vê apenas "o programa está lento", mas números concretos: a função parseData() ocupa 40% do tempo, enquanto loadConfig() aloca 2 GB de memória. Para Go, existem vários tipos de perfis:

\n\n
    \n
  • Perfil de CPU — mostra quais funções consomem tempo de processador.
  • \n
  • Perfil de memória (heap) — mostra quais funções alocam memória e onde os objetos residem.
  • \n
  • Perfil de Goroutine — mostra o número de goroutines ativas e seu estado.
  • \n
  • Perfil de Bloqueio — mostra onde as goroutines estão bloqueadas em mutexes ou canais.
  • \n
  • Perfil de Mutex — mostra a contenção por mutexes.
  • \n
\n\n

Para iniciantes, os mais úteis são os perfis de CPU e Memória. Eles fornecem 80% das respostas para a pergunta "por que o código está lento".

\n\n

Ferramenta pprof: o perfilador integrado do Go

\n\n

Go vem com o pacote integrado net/http/pprof. Ele adiciona endpoints ao seu servidor HTTP, dos quais você pode coletar perfis. Vamos ver um exemplo básico.

\n\n

Passo 1: Conectando pprof à aplicação

\n\n
package main\n\nimport (\n    "fmt"\n    "log"\n    "net/http"\n    _ "net/http/pprof" // conecta o perfilador\n    "time"\n)\n\nfunc main() {\n    // Inicia o servidor na porta 8080\n    go func() {\n        log.Println(http.ListenAndServe("localhost:8080", nil))\n    }()\n\n    // Nossa lógica de negócio "pesada"\n    for i := 0; i < 100; i++ {\n        go heavyTask(i)\n    }\n\n    // Aguarda a conclusão\n    time.Sleep(10 * time.Second)\n    fmt.Println("Done")\n}\n\nfunc heavyTask(id int) {\n    // Simulação de trabalho pesado\n    for i := 0; i < 1000000; i++ {\n        _ = i * i\n    }\n    fmt.Printf("Task %d finished\\n", id)\n}\n
\n\n

Após iniciar a aplicação, abra o navegador em http://localhost:8080/debug/pprof/. Você verá uma interface web com links para os perfis.

\n\n

Passo 2: Coletando o perfil de CPU

\n\n

A maneira mais simples é usar a linha de comando. Execute:

\n\n
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30
\n\n

Este comando coletará o perfil de CPU por 30 segundos. Após a conclusão, o console interativo do pprof será aberto. Digite top para ver as funções mais "quentes":

\n\n
(pprof) top\nShowing nodes accounting for 1.50s, 100% of 1.50s total\n      flat  flat%   sum%        cum   cum%\n     1.50s   100%   100%      1.50s   100%  main.heavyTask\n         0     0%   100%      1.50s   100%  runtime.main\n
\n\n

Aqui, flat é o tempo gasto diretamente dentro da função, e cum é o tempo incluindo chamadas de funções filhas. No nosso exemplo, 100% do tempo é gasto em heavyTask.

\n\n

Passo 3: Visualização via interface web

\n\n

Para uma análise mais visual, use o modo gráfico:

\n\n
go tool pprof -http=:8081 http://localhost:8080/debug/pprof/profile?seconds=30
\n\n

Um navegador será aberto com um gráfico de chamadas interativo. Quanto maior e mais vermelho o bloco, mais recursos ele consome. Esta é uma ótima maneira de encontrar rapidamente funções "pesadas".

\n\n

Perfilamento de memória:

Blogs

Book Recommendations