Voltar ao Blog

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.

2 min read
.NETC#performance

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-SampleProfiler

Conclusã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.