Otimização de desempenho de aplicações C#: 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

Introdução: por que o desempenho é importante desde o início?

\n

Todo desenvolvedor C# mais cedo ou mais tarde se depara com uma situação em que a aplicação começa a ficar lenta. Frequentemente, os problemas de desempenho são introduzidos nas fases iniciais — devido a algoritmos não otimizados, gerenciamento incorreto de memória ou uso excessivo de LINQ sem entender seu funcionamento interno. Para iniciantes, este tópico pode parecer complexo, mas, na verdade, os princípios básicos de otimização são bastante simples e podem ser aprendidos em algumas horas de prática.

\n

Neste artigo, abordaremos quatro aspectos-chave que o ajudarão a escrever aplicações C# rápidas e eficientes na plataforma .NET. Você aprenderá como criar perfis de código, otimizar consultas LINQ, gerenciar a memória corretamente e usar assincronia. Os exemplos de código serão o mais próximos possível de tarefas reais que os desenvolvedores enfrentam.

\n\n

1. Criação de perfil: o primeiro passo para a otimização

\n

Antes de otimizar qualquer coisa, é preciso entender o que está causando a lentidão. Palpites intuitivos são frequentemente errados. A criação de perfil é o processo de medir o desempenho do seu código usando ferramentas especiais.

\n\n

Ferramentas para criação de perfil

\n
    \n
  • Ferramentas de Diagnóstico do Visual Studio — ferramenta integrada, disponível nas edições Community e superiores. Permite monitorar o uso de CPU, memória e tempo de execução.
  • \n
  • JetBrains dotMemory / dotTrace — poderosas utilidades comerciais para análise de memória e tempo de execução.
  • \n
  • BenchmarkDotNet — biblioteca leve para microbenchmarking. Ideal para comparar duas implementações de um mesmo método.
  • \n
\n\n

Exemplo: medindo o tempo de execução

\n

Usamos Stopwatch para uma medição simples:

\n
using System.Diagnostics;\n\nvar stopwatch = Stopwatch.StartNew();\n// Seu código\nfor (int i = 0; i < 1000000; i++)\n{\n    // Alguma operação\n}\nstopwatch.Stop();\nConsole.WriteLine($"Tempo de execução: {stopwatch.ElapsedMilliseconds} ms");
\n

Dica: para medições precisas, use BenchmarkDotNet, pois o Stopwatch não considera a sobrecarga da compilação JIT.

\n\n

2. Gerenciamento de memória e strings

\n

O gerenciamento de memória no .NET é automatizado (Garbage Collector), mas isso não significa que você pode ignorá-lo. Um dos problemas mais comuns é a criação excessiva de strings.

\n\n

Problema: concatenação de strings em loop

\n

Strings em C# são imutáveis. Cada operação + cria uma nova string, o que leva a alocações constantes e pressão sobre o GC:

\n
string result = "";\nfor (int i = 0; i < 10000; i++)\n{\n    result += i.ToString(); // RUIM: cria 10000 novas strings\n}
\n\n

Solução: StringBuilder

\n

A classe StringBuilder trabalha com um buffer de caracteres e minimiza as alocações:

\n
var sb = new StringBuilder();\nfor (int i = 0; i < 10000; i++)\n{\n    sb.Append(i);\n}\nstring result = sb.ToString(); // BOM: uma alocação no final
\n\n

Evite boxing

\n

Boxing (empacotamento de tipos de valor em um objeto) é outra fonte de alocações ocultas. Exemplo:

\n
ArrayList list = new ArrayList();\nlist.Add(42); // Boxing: int é empacotado em object\n\n// Melhor usar coleções genéricas:\nList<int> list2 = new List<int>();\nlist2.Add(42); // Sem boxing
\n\n

3. Otimização de consultas LINQ

\n

LINQ é uma ferramenta poderosa, mas seu uso incorreto pode tornar a aplicação muito mais lenta. O principal problema são as múltiplas iterações sobre coleções.

\n\n

Problema: iterações múltiplas

\n

Cada chamada a Where(), Select(), Count() pode iterar sobre a coleção novamente, se o resultado não for materializado:

\n
var numbers = Enumerable.Range(1, 1000000);\nvar evenNumbers = numbers.Where(n => n % 2 == 0);\nint coun                

Blogs

Book Recommendations