.NET Integer vs Int16?

Tengo una práctica de encoding cuestionable.

Cuando necesito iterar a través de una pequeña lista de elementos cuyo límite de recuento es inferior a 32000 , uso Int16 para mi tipo de variable i en lugar de Integer . Hago esto porque asumo que usar el Int16 es más eficiente que un entero completo.

¿Me equivoco? ¿No hay una diferencia de rendimiento efectiva entre el uso de un Int16 vs un Integer ? ¿Debería dejar de usar Int16 y Int16 a Integer para todas mis necesidades de conteo / iteración?

De acuerdo con la referencia a continuación, el tiempo de ejecución optimiza el rendimiento de Int32 y lo recomienda para contadores y otras operaciones a las que se accede con frecuencia.

Del libro: MCTS Self-Paced Training Kit (Examen 70-536): Microsoft® .NET Framework 2.0-Application Development Foundation

Capítulo 1: “Fundamentos del marco”
Lección 1: “Uso de tipos de valores”

Mejores prácticas: optimización del rendimiento con tipos incorporados

El tiempo de ejecución optimiza el rendimiento de los tipos enteros de 32 bits (Int32 y UInt32), por lo tanto, use esos tipos para los contadores y otras variables integrales a las que se accede con frecuencia.

Para operaciones de coma flotante, Double es el tipo más eficiente porque esas operaciones están optimizadas por hardware.

Además, la Tabla 1-1 en la misma sección enumera los usos recomendados para cada tipo. Pertinente a esta discusión:

  • Int16 – Interoperación y otros usos especializados
  • Int32 – Números enteros y contadores
  • Int64 – Números enteros grandes

Casi siempre debe usar Int32 o Int64 (y, no, no obtiene crédito usando UInt32 o UInt64 ) al UInt64 sobre una matriz o colección por índice.

La razón más obvia de que es menos eficiente es que todos los índices de matriz y colección que se encuentran en el BCL toman Int32 s, por lo que siempre Int32 un lanzamiento implícito en el código que intente usar Int16 s como índice.

La razón menos obvia (y la razón por la que las matrices toman Int32 como índice) es que la especificación CIL dice que todos los valores de la stack de operación son Int32 o Int64 . Cada vez que carga o almacena un valor en cualquier otro tipo entero ( Byte , SByte , UInt16 , Int16 , UInt32 o UInt64 ), se trata de una operación de conversión implícita. Los tipos sin firmar no tienen penalización por la carga, pero para almacenar el valor, esto equivale a un truncamiento y una posible verificación de desbordamiento. Para los tipos firmados, cada signo de carga (se extiende, y cada signo de tienda) se contrae (y tiene una posible verificación de desbordamiento).

El lugar donde más te afectará es el bucle en sí, no el conjunto de accesos. Por ejemplo, tome este ciclo de aspecto inocente:

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

Se ve bien, ¿verdad? ¡No! Básicamente puede ignorar la inicialización ( short i = 0 ) ya que solo ocurre una vez, pero las partes de comparación ( i<32000 ) e incremento ( i++ ) ocurren 32000 veces. Aquí hay un código pesudo para lo que esto parece a nivel de 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: 

Hay 3 conversiones allí que se ejecutan 32000 veces. Y podrían haberse evitado por completo con solo usar un Int32 o Int64 .

Actualización: Como dije en el comentario, ahora, de hecho, escribí una publicación de blog sobre este tema, Tipos de datos integrales .NET y usted

Int16 en realidad puede ser menos eficiente porque las instrucciones x86 para el acceso de palabra ocupan más espacio que las instrucciones para el acceso de dword. Dependerá de lo que haga el JIT. Pero pase lo que pase, es casi seguro que no es más eficiente cuando se usa como la variable en una iteración.

El opuesto es verdad.

32 (o 64) bits enteros son más rápidos que int16. En general, el tipo de datos nativo es el más rápido.

Int16 es agradable si desea que sus estructuras de datos sean lo más ajustadas posible. Esto ahorra espacio y puede mejorar el rendimiento.

Cualquier diferencia de rendimiento será tan pequeña en el hardware moderno que, para todos los efectos, no hará ninguna diferencia. Intenta escribir un par de arneses de prueba y ejecútalos unos cientos de veces, realiza los tiempos promedio de finalización del bucle y verás a qué me refiero.

Podría tener sentido desde el punto de vista del almacenamiento si tiene recursos muy limitados: sistemas integrados con una pequeña stack, protocolos de cable diseñados para redes lentas (por ejemplo, GPRS, etc.), y así sucesivamente.

Nunca asums la eficiencia.

Lo que es o no es más eficiente variará de comstackdor a comstackdor y plataforma a plataforma. A menos que realmente haya probado esto, no hay forma de saber si int16 o int es más eficiente.

Solo me quedaría con los enteros a menos que te encuentres con un problema de rendimiento probado que usa arreglos int16.

Utilice Int32 en máquinas de 32 bits (o Int64 en máquinas de 64 bits) para un rendimiento más rápido. Utilice un tipo entero más pequeño si realmente está preocupado por el espacio que ocupa (aunque puede ser más lento).

Los otros aquí son correctos, solo use menos de Int32 (para código de 32 bits) / Int64 (para código de 64 bits) si lo necesita para requisitos de almacenamiento extremos, o para otro nivel de cumplimiento en un campo de objeto comercial (debe todavía tiene validación de nivel de propiedad en este caso, por supuesto).

Y, en general, no se preocupe por la eficacia hasta que haya un problema de rendimiento. Y en ese caso, perfilarlo. Y si adivinar y verificar con ambas formas mientras que el perfil no le ayuda lo suficiente, verifique el código IL.

Buena pregunta sin embargo. Estás aprendiendo más sobre cómo lo hace el comstackdor. Si desea aprender a progtwigr de manera más eficiente, aprender los conceptos básicos de IL y cómo hacen los comstackdores C # / VB su trabajo sería una gran idea.

No puedo imaginar que haya una ganancia de rendimiento significativa en Int16 vs. int.

Guarda algunos bits en la statement de la variable.

Y definitivamente no vale la pena la molestia cuando las especificaciones cambian y lo que sea que estés contando puede ir por encima de 32767 ahora y descubres que cuando tu aplicación comienza a lanzar excepciones …

No hay una ganancia de rendimiento significativa en el uso de un tipo de datos más pequeño que Int32, de hecho, leí en algún lugar que el uso de Int32 será más rápido que Int16 debido a la asignación de memoria