Dicas de performance em .NET
Práticas concretas para melhorar throughput e reduzir latência em aplicações .NET modernas — do pooling de objetos ao uso correto de async.
Performance em .NET não é magia: é sobre medir, entender o gargalo e aplicar a otimização certa. Aqui vão algumas dicas que uso em produção.
1. Prefira ArrayPool e ObjectPool para alocações quentes
Em hot paths, evitar alocações é mais importante do que micro-otimizar algoritmos. O ArrayPool<T> reutiliza buffers e reduz a pressão no GC.
using System.Buffers;
public byte[] ProcessData(ReadOnlySpan<byte> input)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(input.Length);
try
{
// ...processa usando buffer...
input.CopyTo(buffer);
return buffer[..input.Length].ToArray();
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}2. Use async corretamente
async não é sinônimo de "rápido". O overhead de uma state machine existe. Para operações realmente síncronas e baratas, evite async.
public async Task<User> GetUserAsync(int id)
{
await using var ctx = new AppDbContext();
return await ctx.Users
.AsNoTracking()
.FirstOrDefaultAsync(u => u.Id == id)
.ConfigureAwait(false);
}Use
ConfigureAwait(false)em código de biblioteca para evitar capturar o contexto de sincronização.
3. Evite LINQ em hot loops
LINQ é lindo, mas cria closures e iterações extras. Em loops de alta frequência, prefira for:
int sum = 0;
for (int i = 0; i < items.Length; i++)
{
sum += items[i].Value;
}4. Meça antes de otimizar
Use dotnet-counters, dotnet-trace e o BenchmarkDotNet antes de mudar qualquer coisa. Otimizar sem medir é apagar incêndio imaginário.
dotnet trace collect --providers Microsoft-DotNETCore-SampleProfilerConclusão
Performance é acumulada: cada redução de alocação, cada ConfigureAwait(false), cada loop convertido de LINQ para for contribui para uma aplicação mais saudável em produção.