.NET Integer vs Int16?

Eu tenho uma prática de codificação questionável.

Quando preciso percorrer uma pequena lista de itens cujo limite de contagem é inferior a 32000 , uso Int16 para o tipo de variável i em vez de Integer . Eu faço isso porque eu suponho que usar o Int16 é mais eficiente que um Integer completo.

Estou errado? Não há diferença efetiva de desempenho entre usar um Int16 vs um Integer ? Devo parar de usar Int16 e ficar com Integer para todas as minhas necessidades de contagem / iteração?

De acordo com a referência abaixo, o tempo de execução otimiza o desempenho do Int32 e os recomenda para contadores e outras operações freqüentemente acessadas.

A partir do livro: Kit de treinamento em ritmo individual MCTS (exame 70-536): Microsoft® .NET Framework 2.0 – Application Development Foundation

Capítulo 1: “Fundamentos do Framework”
Lição 1: “Usando tipos de valor”

Melhores práticas: Otimizando o desempenho com tipos incorporados

O tempo de execução otimiza o desempenho de tipos inteiros de 32 bits (Int32 e UInt32), portanto, use esses tipos para contadores e outras variables ​​integrais acessadas com freqüência.

Para operações de ponto flutuante, Double é o tipo mais eficiente, porque essas operações são otimizadas pelo hardware.

Além disso, a Tabela 1-1 na mesma seção lista os usos recomendados para cada tipo. Relevante para esta discussão:

  • Int16 – Interoperação e outros usos especializados
  • Int32 – Números e contadores inteiros
  • Int64 – Grandes números inteiros

Você deve quase sempre usar Int32 ou Int64 (e, não, você não recebe crédito usando UInt32 ou UInt64 ) ao fazer o loop em uma matriz ou coleção por índice.

A razão mais óbvia que é menos eficiente é que todos os índices de array e coleção encontrados na BCL levam Int32 s, portanto, um casting implícito sempre ocorrerá no código que tenta usar Int16 s como um índice.

O motivo menos óbvio (e o motivo pelo qual os arrays usam o Int32 como um índice) é que a especificação CIL diz que todos os valores da pilha de operações são Int32 ou Int64 . Toda vez que você carregar ou armazenar um valor em qualquer outro tipo inteiro ( Byte , SByte , UInt16 , Int16 , UInt32 ou UInt64 ), haverá uma operação de conversão implícita envolvida. Tipos não assinados não têm penalidade pelo carregamento, mas, para armazenar o valor, isso equivale a um truncamento e a uma possível verificação de estouro. Para os tipos assinados, todos os sinais de carga se estendem, e todos os sinais de loja se acumulam (e tem uma possível verificação de estouro).

O lugar que isso vai te machucar mais é o loop em si, não o array acessa. Por exemplo, pegue este loop inocente:

 for (short i = 0; i < 32000; i++) { ... } 

Parece bom, certo? Não! Você pode basicamente ignorar a boot ( short i = 0 ), uma vez que isso só acontece uma vez, mas as partes de comparação ( i<32000 ) e de incremento ( i++ ) acontecem 32000 vezes. Aqui está algum pesudo-código para o que esta coisa se parece no nível da máquina:

  Int16 i = 0; LOOP: Int32 temp0 = Convert_I16_To_I32(i); // !!! if (temp0 >= 32000) goto END; ... Int32 temp1 = Convert_I16_To_I32(i); // !!! Int32 temp2 = temp1 + 1; i = Convert_I32_To_I16(temp2); // !!! goto LOOP; END: 

Existem 3 conversões que são executadas 32000 vezes. E eles poderiam ter sido completamente evitados usando apenas um Int32 ou Int64 .

Atualização: Como eu disse no comentário, escrevi agora, na verdade, uma postagem de blog sobre esse tópico, os tipos de dados integrais do .NET e você

O Int16 pode na verdade ser menos eficiente porque as instruções do x86 para access à palavra ocupam mais espaço do que as instruções para access ao dword. Dependerá do que o JIT faz. Mas não importa o quê, quase certamente não é mais eficiente quando usado como a variável em uma iteração.

O oposto é verdadeiro.

32 (ou 64) bits inteiros são mais rápidos que int16. Em geral, o tipo de dados nativo é o mais rápido.

Int16 são bons se você quiser tornar suas estruturas de dados o mais simples possível. Isso economiza espaço e pode melhorar o desempenho.

Qualquer diferença de desempenho será tão pequena no hardware moderno que, para todos os efeitos, não fará diferença. Tente escrever alguns chicotes de teste e execute-os algumas centenas de vezes, faça o tempo médio de conclusão do loop e você verá o que quero dizer.

Pode fazer sentido, do ponto de vista do armazenamento, se você tiver resources muito limitados – sistemas embarcados com uma pequena pilha, protocolos de fios projetados para redes lentas (por exemplo, GPRS, etc.) e assim por diante.

Nunca assuma a eficiência.

O que é ou não é mais eficiente irá variar de compilador para compilador e de plataforma para plataforma. A menos que você realmente tenha testado isso, não há como saber se int16 ou int é mais eficiente.

Eu iria ficar com ints a menos que você se deparar com um problema de desempenho comprovado que usa correções int16.

Use Int32 em máquinas de 32 bits (ou Int64 em máquinas de 64 bits) para desempenho mais rápido. Use um tipo inteiro menor se você estiver realmente preocupado com o espaço ocupado (pode ser mais lento, no entanto).

Os outros aqui estão corretos, use somente menos que Int32 (para código de 32 bits) / Int64 (para código de 64 bits) se você precisar dele para requisitos extremos de armazenamento ou para outro nível de imposição em um campo de object de negócios ainda tem validação de nível propery neste caso, é claro).

E, em geral, não se preocupe com a eficiência até que haja um problema de desempenho. E nesse caso, faça o perfil dele. E se adivinhar e verificar com ambas as formas enquanto o perfil não ajuda bastante, verifique o código IL.

Boa pergunta embora. Você está aprendendo mais sobre como o compilador faz sua coisa. Se você quiser aprender a programar mais eficientemente, aprender os fundamentos do IL e como os compiladores C # / VB fazem o seu trabalho seria uma ótima idéia.

Não consigo imaginar que haja algum ganho significativo de desempenho em Int16 vs. int.

Você salva alguns bits na declaração da variável.

E definitivamente não vale a pena o incômodo quando as especificações mudam e o que você está contando pode ir acima de 32767 agora e você descobre que quando seu aplicativo começa a lançar exceções …

Não há ganho de desempenho significativo em usar um tipo de dados menor que Int32, na verdade, eu li em algum lugar que usar Int32 será mais rápido que Int16 por causa da alocação de memory