Perfilamento de código C#: encontre gargalos e acelere aplicações

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 a criação de perfil é importante

Todo desenvolvedor C# já passou por uma situação em que o aplicativo funciona lentamente, mas não está claro o porquê. Palpites intuitivos geralmente são errôneos: o código que parece lento pode ser rápido, e "otimizações" óbvias podem ser inúteis. É aqui que a criação de perfil (profiling) vem ao socorro — uma análise sistemática do desempenho do código para identificar gargalos.

A criação de perfil em .NET não é apenas medir o tempo de execução. É todo um conjunto de técnicas: desde um simples Stopwatch até ferramentas avançadas como BenchmarkDotNet e PerfView. Sem a criação de perfil, você corre o risco de otimizar o que não precisa, perdendo horas em mudanças inúteis.

Neste artigo, vamos analisar métodos práticos de criação de perfil de código C#, aprender a encontrar gargalos reais e entender quais ferramentas usar em cada caso específico.



1. Criação de perfil básica com Stopwatch

A maneira mais simples de medir o tempo de execução é usar a classe System.Diagnostics.Stopwatch. Ela é adequada para verificações rápidas e cenários simples, mas tem limitações: alto overhead (nanossegundos) e falta de estatísticas.

using System.Diagnostics;

public class SimpleProfiler{ public static void Measure() { var sw = Stopwatch.StartNew(); // Código a ser testado var list = Enumerable.Range(0, 10_000_000).ToList(); sw.Stop(); Console.WriteLine($"Tempo: {sw.ElapsedMilliseconds} ms"); }}

Quando usar: para uma estimativa grosseira, quando você precisa de uma resposta rápida sem instalar pacotes adicionais. Não é adequado para medições precisas (por exemplo, ao comparar algoritmos).

Desvantagens: uma medição única pode ser aleatória (GC, processos em segundo plano). É necessário executar várias vezes e calcular a média — isso é exatamente o que o BenchmarkDotNet faz.



2. BenchmarkDotNet: o padrão ouro para benchmarks

BenchmarkDotNet é uma biblioteca para criar benchmarks precisos e reproduzíveis. Ela aquece automaticamente o JIT, evita a influência do GC e fornece estatísticas detalhadas.

Instalação e exemplo básico

// Instalação: dotnet add package BenchmarkDotNetusing BenchmarkDotNet.Attributes;using BenchmarkDotNet.Running;

public class StringBenchmark{ private string _text = "Hello, World!"; [Benchmark] public bool ContainsWithOrdinal() => _text.Contains("World", StringComparison.Ordinal); [Benchmark] public bool ContainsWithInvariant() => _text.Contains("World", StringComparison.InvariantCulture);}

class Program{ static void Main() => BenchmarkRunner.Run<StringBenchmark>();}

O resultado mostrará que Ordinal é 2-3 vezes mais rápido. Sem o benchmark, você não notaria isso.

Recursos avançados

  • Parâmetros: teste com diferentes tamanhos de dados.
  • MemoryDiagnoser: mostra alocações de memória.
  • Baseline: compare o desempenho com uma referência.
[MemoryDiagnoser]public class ListBenchmark{    [Params(100, 1000, 10000)]    public int N;        private List<int> _list;        [GlobalSetup]    public void Setup() => _list = Enumerable.Range(0, N).ToList();        [Benchmark(Baseline = true)]    public int ForLoop()    {        int sum = 0;        for (int i = 0; i < _list.Count; i++) sum += _list[i];        return sum;    }        [Benchmark]    public int ForeachLoop()    {        int sum = 0;        foreach (var item in _list) sum += item;        return sum;    }}


3. Criação de perfil de memória e GC

Vazamentos de memória e coletas de lixo frequentes são uma causa comum de lentidão em .NET. Para análise, use:

3.1. Memory Profiler (JetBrains dotMemo

Blogs

Book Recommendations