Domine async/await no C# 13: melhore desempenho e clareza
C# 13: Domine Tipos e Otimize o Desempenho do Código
Neste tutorial, você aprenderá como fazer escolhas adequadas de tipos para maximizar o desempenho em aplicações C# 13O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET.. Abordaremos desde o uso inteligente de valores e referências até recursos como
Span<T>
, structs e classesBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC., explorando também boas práticas para reduzir alocações desnecessárias e, assim, otimizar a velocidade de execução.
Entendendo a Importância de Escolher o Tipo Correto🔗
Cada tipo em C# 13O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET. possui características de alocação de memória, transferência de dados e tratamento em tempo de execução que influenciam diretamente a performance. Quando falamos em tipos por valor
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. (Value Types), estamos lidando com dados que, em geral, são armazenados na stack (pilha). Já os tipos por referência (Reference Types
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.) ficam no heap, exigindo acesso indireto por ponteiros internos.
Por que isso importa? Porque toda chamada de método, uso de coleções e até loops de alto volume podem gerar um impacto significativo, acumulado ao longo de milhares ou milhões de iterações.
Struct vs. Class: Quando Usar Cada Tipo🔗
Um debate clássico em C#: structBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. ou class
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.? Em C# 13
O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET., as regras básicas continuam:
- struct
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. (tipo por valor):
- Geralmente aconselhável quando a estrutura é pequena e imutável (ou com poucas mutações).
- Boa para reduzir o overhead de alocação no heap.
- Útil em cenários de alto volume de instâncias ou chamadas frequentes (ex.: game loops ou manipulação de dados sensíveis em processamento intensivo).
- class
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. (tipo por referência):
- Adequada para objetos complexos, com muitos campos ou forte vinculação hierárquica (herança).
- Permite comportamentos polimórficos clássicos.
Uma novidade que facilita a decisão é o maior suporte a tipos record struct
e Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
record class
, permitindo criar tipos mais otimizados e com benefícios de boilerplate reduzido, como comparações estruturais (“por valor semântica”) e deconstruction. Entretanto, quando se fala apenas em desempenho, considere se realmente precisa de todos os recursos de uma classBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. antes de optar por ela.
Usando Span<T> para Evitar Cópias Desnecessárias🔗
O Span<T>
permite manipular blocos de memória contíguos sem criar novas alocações. Em vez de copiar arrays ou strings durante operações de slicing e leitura, você trabalha diretamente sobre a mesma região de memória.
Por exemplo, considere este trecho de código para acessar um intervalo de um array:
int[] numeros = { 10, 20, 30, 40, 50 };
// Abordagem sem Span<T>
// Cria um novo array com elementos de índice 1 a 3
int[] subNumeros = numeros[1..4];
// Com Span<T>, reaproveita memória
Span<int> spanNumeros = new Span<int>(numeros);
Span<int> slice = spanNumeros.Slice(1, 3);
// Agora 'slice[0]' corresponde diretamente ao 'numeros[1]'
Benefícios:
- Evita alocações extras e cópias de dados.
- Torna o código mais fluido para manipular fatias de arrays e strings.
- Integra-se muito bem a cenários de alto desempenho, como processamentos de stream ou buffers de rede.
Classes Seladas (sealed) para Evitar Sobrecarga de Herança🔗
Mesmo sendo um recurso já existente antes do C# 13O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET., o uso de
sealed class
continua relevante quando a intenção é bloquear herança e otimizar chamadas de método. O tempo de execução do .NET (CLR) pode efetuar diversas otimizações em classesBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. seladas, pois sabe que não ocorrerá polimorfismo dinâmico.
public sealed class Calculadora
{
public int Somar(int a, int b) => a + b;
}
Por que selar a classe melhora desempenho?
- O CLR pode fazer inlining e devirtualização de chamadas de métodos em classes
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. sealed, pois não serão sobrescritos.
- Reduz a complexidade de possíveis lookups na vtable.
ValueTask Versus Task: Quando Optar pelo ValueTask🔗
Para operações assíncronas que podem terminar de forma imediata ou ter pouco trabalho a ser feito, ValueTask
é útil. Diferentemente de Task
, que é sempre alocado no heap, um ValueTask
pode funcionar como uma structBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. simples e evitar uma alocação adicional caso o resultado já esteja disponível:
// Exemplo de método que se beneficia de ValueTask
public async ValueTask<int> CalcularAlgoAsync(int x)
{
if (x < 10)
{
// Retorna com computação imediata, sem criar uma Task no heap
return x + 10;
}
// Caso contrário, processa de forma assíncrona
await Task.Delay(100);
return x + 100;
}
Quando usar?
- Em métodos muito simples, chamados com alta frequência.
- Em bibliotecas de baixo nível onde cada alocação faz diferença.
- Se o método for mais complexo ou não for chamado repetidamente, o ganho pode ser mínimo ou inexistente em comparação ao
Task
.
Minimizar Boxing e Unboxing🔗
Boxing ocorre quando um tipo por valor (ex.: int
, struct
, Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
bool
) é convertido para object
ou para uma interfaceTrabalhando com interfaces e coleções aprimoradas em C# 13Descubra como as implementações padrão em interfaces e coleções aprimoradas do C# 13 otimizam a criação de códigos modulares, seguros e performáticos. implementada por ele. Unboxing é a operação inversa. Em aplicações com intensas operações de conversão, isso resulta em muitas alocações desnecessárias de objetos.
Uma dica para C# 13O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET. (e em versões anteriores também) é evitar passes redundantes por
object
ou interfacesTrabalhando com interfaces e coleções aprimoradas em C# 13Descubra como as implementações padrão em interfaces e coleções aprimoradas do C# 13 otimizam a criação de códigos modulares, seguros e performáticos. genéricas quando não for essencial. Em vez disso, use tipos genéricos fortes e overloads de método dedicadas a tipos valor, sempre que possível.
Structs Imutáveis e readonly struct🔗
Quando você decide usar struct
, considere se ela pode ser imutável. Structs imutáveis previnem modificações acidentais no estado interno, o que favorece otimizações do compilador. Já a palavra-chave Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
readonly
garante que todos os campos da structBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. são apenas leitura, fornecendo mais segurança para otimizações ao gerar código compilado.
public readonly struct Ponto2D
{
public Ponto2D(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
}
Benefícios:
- Menos gastos de cópia e defesa de estado.
- Maior clareza de que o valor não será alterado após a criação.
Exemplos de Comparação de Desempenho🔗
Para ilustrar, abaixo está uma pequena tabela de situações de uso onde cada escolha traz impacto no desempenho (valores hipotéticos apenas para exemplificar a ideia):
Situação | Abordagem Recomendada | Motivo |
---|---|---|
Alto volume de acesso a arrays | Span<T> | Evita cópias, reduz alocações desnecessárias |
Estrutura leve e imutável | readonly struct ou record struct | Elimina overhead de heap, facilita otimizadores |
Operações assíncronas simples | ValueTask | Evita alocação de Task no heap em cenários de rápido retorno |
Herança desnecessária | sealed class | Permite otimizações de inlining e devirtualização no CLR |
Conversões frequentes | Evitar boxing/unboxing por object | Minimiza alocações e tempo de casting |
Conclusão🔗
Nesta etapa do aprendizado, vimos como o uso correto de tipos é essencial para aplicar otimizações de desempenho em C# 13O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET., mantendo a legibilidade. Ao prestar atenção às distinções entre struct
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. e class
Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC., empregar
Span<T>
para manipular coleções sem overhead, escolher ValueTask
em cenários assíncronos pontuais e selar classesBoas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC. que não requerem herança, você atinge um código mais responsivo, com melhor gerenciamento de memória.
A chave está em entender o seu domínio e escolher o tipo mais adequado às necessidades de cada segmento de código. Pequenos ajustes podem gerar grandes ganhos acumulados em aplicações de grande porte ou em cenários de alta concorrência.
Próximos Passos
- Exercite o uso de
Span<T>
em processamento de arrays e strings. - Experimente converter métodos que retornam
Task
paraValueTask
e observe os ganhos de performance em cenários simples. - Avalie se faz sentido aplicar
sealed class
onde não há necessidade de herança.Boas práticas de performance e memória para jogos em C# 13Descubra técnicas para otimizar desempenho e uso de memória em jogos com C# 13, utilizando structs, pooling e melhores práticas do GC.
- Crie e teste structs e record structs para aproveitar as otimizações oferecidas pelo C# 13
O que é C# 13 e por que aprender em 90 minutosExplore as inovações do C# 13 e melhore a legibilidade do seu código. Este tutorial prático de 90 minutos oferece dicas essenciais para desenvolvedores .NET..
Com essas práticas, você se aproxima de um código robusto, com alta eficiência e pronto para lidar com cenários escaláveis.
Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.
Referências🔗
- Documentação Oficial Microsoft sobre C# - Fornece as bases oficiais e detalhadas sobre a linguagem e os recursos apresentados no tutorial, como tipos de valor, Span<T>, e otimizações no gerenciamento de memória: docs.microsoft.com/pt-br/dotnet/csharp/