2009-07-08 11 views
51

? He encontrado algunos hilos en relación con este problema. La mayoría de las personas parece favorecer el uso de int en su código C# en todo el tablero, incluso si un byte o smallint manejaría los datos a menos que sea una aplicación móvil. No entiendo por qué. ¿No tiene más sentido definir su tipo de datos C# como el mismo tipo de datos que estaría en su solución de almacenamiento de datos?¿Por qué debería usar int en lugar de un byte o abreviar en C#

Mi premisa: Si utilizo un conjunto de datos tipeados, clases de Linq2SQL, POCO, de una forma u otra me encontraré con problemas de conversión del tipo de datos de compilación si no mantengo mis tipos de datos sincronizados en mis niveles. Realmente no me gusta hacer el System.Convert todo el tiempo solo porque era más fácil de usar int en todo el tablero en el código C#. Siempre utilicé el tipo de datos más pequeño que sea necesario para manejar los datos en la base de datos y en el código, para mantener limpia mi interfaz con la base de datos. Así que apostaría a que el 75% de mi código C# usa byte o short en lugar de int, porque eso es lo que hay en la base de datos. Posibilidades: Esto significa que la mayoría de las personas que usan int para todo en código también usan el tipo de datos int para sus tipos de datos de almacenamiento sql y no les importa el tamaño total de su base de datos, o lo hacen system.convert en el código donde sea aplicable?

Por qué me importa: he trabajado por mi cuenta para siempre y solo quiero estar familiarizado con las mejores prácticas y las convenciones de codificación estándar.

+0

pregunta original dejó la impresión de que me estaba preguntando si había alguna razón por la que debería evitar byte o smallint a favor de la int. que realmente quieren saber por qué es mejor utilizar int todas partes en lugar de byte o smallint cuando bastarían esos tipos de datos. – Breadtruck

+0

lo tanto, si el usuario acepta usar int todas partes Quiero saber cuál es el beneficio por así decirlo, un mejor rendimiento, sin conversiones, ¿por qué debería utilizar int todas partes – Breadtruck

Respuesta

70

En cuanto a rendimiento, un int es más rápido en casi todos los casos. La CPU está diseñada para funcionar de manera eficiente con valores de 32 bits.

Los valores más cortos son complicados de manejar. Para leer un solo byte, por ejemplo, la CPU debe leer el bloque de 32 bits que lo contiene y luego enmascarar los 24 bits superiores.

Para escribir un byte, tiene que leer el bloque de 32 bits de destino, sobrescribir los 8 bits inferiores con el valor de byte deseado y volver a escribir todo el bloque de 32 bits.

Desde el punto de vista del espacio, por supuesto, ahorrará unos pocos bytes mediante el uso de tipos de datos más pequeños. Entonces, si está construyendo una tabla con unos pocos millones de filas, vale la pena considerar los tipos de datos más cortos. (Y la misma podría ser una buena razón por la cual debería usar tipos de datos más pequeños en su base de datos)

Y en cuanto a la corrección, un int no se desborda fácilmente. ¿Qué pasa si piensa que su valor va a caber dentro de un byte, y luego, en algún momento en el futuro, un cambio inofensivo al código significa que se almacenan valores más grandes en él?

Esas son algunas de las razones por las cuales int debe ser su tipo de datos predeterminado para todos los datos integrales. Solo use byte si realmente desea almacenar bytes de máquina. Solo use cortos si está tratando con un formato de archivo o protocolo o similar que realmente especifique valores enteros de 16 bits. Si solo estás tratando con enteros en general, hazlos enteros.

+0

Creo que es otro caso donde es o.k. usar byte/short es cuando recibes argumentos en un método/propiedad y sabes, por definición, que debe estar restringido a valores de 8/16-bit. De lo contrario, las únicas opciones (más graves en mi opinión) que veo son: 1. Ignorando valores incorrectos 2. Recortar valores incorrectos 3. Planteando una excepción – maayank

+0

@maayank: Incluso si usted sabe que los valores siempre están restringidos, todavía hay dos problemas: 1) ¿qué sucede si cambio el código más tarde, para que se puedan pasar valores más grandes, lo que sobrecargaría mi innecesariamente estrecha variable de 8/16 bits, y 2) por qué lo haría, cuando se usa un valor de 32 bits? generalmente más rápido? – jalf

+1

¿Debo usar 'long' de forma predeterminada en máquinas de 64 bits? (Si está interesado, por favor, eche un vistazo a [esta pregunta] (http://stackoverflow.com/questions/6825023/should-i-use-long-instead-of-int-on-64-bits-in -langs-with-fixed-type-size-li)) –

6

En su mayor parte, 'No'.

A menos que sepa de antemano que va a tratar con cientos de millones de filas, se trata de una micro-optimización.

Haga lo que mejor se adapte al modelo de Dominio. Más tarde, si tiene problemas de rendimiento, punto de referencia y perfil para señalar dónde están ocurriendo.

+3

Creo que está diciendo 'no' a la utilización de este tipo, aunque es ligeramente ambiguo con la pregunta que pregunta si evitarlos. De todos modos, es un buen consejo con respecto a la micro-optimización. – Noldorin

+1

¿Entonces los dos están sugiriendo quedarse con int en todos los ámbitos a menos que sus millones de filas y su manejo de micro-optimización? – Breadtruck

+1

Sí, para adherirse a int, a menos que en el dominio una minúscula (por ejemplo) tenga más sentido. Cuando digo micro-optimización, quiero decir que es una mala idea. No es la forma de optimizar. –

4

Si int se usa en todas partes, no se requieren conversiones ni conversiones. Esa es una mayor inversión para la pelota que la memoria que ahorrará al usar múltiples tamaños enteros.

Simplemente hace la vida más simple.

4

.NET runtime está optimizado para Int32. Ver discusión anterior en .NET Integer vs Int16?

+0

No creo que se trata de tiempo de ejecución de .NET, pero x86 .. – nawfal

8

que tendría que estar tratando con algunos mil millones filas antes de que esto hace ninguna diferencia significativa en términos de capacidad de almacenamiento. Digamos que tiene tres columnas, y en lugar de usar un tipo de base de datos equivalente a bytes, usa un int-equivalent.

Eso nos da 3 (columnas) x 3 (bytes adicionales por fila), o 9 bytes por fila.

Esto significa, por "unos pocos millones de filas" (digamos que tres millones), que se consume en su conjunto 27 megabytes adicionales de espacio en disco! Afortunadamente, como ya no vivimos en la década de 1970, no debería tener que preocuparse por esto :)

Como dije anteriormente, detenga la micro-optimización - el rendimiento alcanzado al convertir a/de diferentes tipos numéricos enteros te va a golpear mucho, mucho más duro que los costos de ancho de banda/espacio de disco, a menos que estés tratando con conjuntos de datos muy, muy grandes.

5

No es que yo no creía Jon Grant y otros, pero tenía que ver por mí mismo con nuestro "millones de fila de la tabla". La mesa tiene 1,018,000. Convertí 11 columnas tinyint y 6 columnas smallint en int, ya había 5 int & 3 smalldatetimes. 4 índices diferentes usaron una combinación de varios tipos de datos, pero obviamente los nuevos índices ahora están usando columnas int.

Hacer los cambios sólo me costó 40 mb cálculo de uso de disco tabla base sin índices. Cuando agregué los índices nuevamente en el cambio general, solo hubo 30 mb de diferencia en general. Así que me sorprendió porque pensé que el tamaño del índice sería más grande.

Así es de 30 mb vale la pena la molestia de usar todos los diferentes tipos de datos, de ninguna manera! Me voy a tierra INT, gracias a todos por volver a configurar este programador anal retentivo en la recta y feliz vida feliz de no más conversiones de enteros ... ¡yippeee!

+2

¿Y qué pasa con db cash? Es un factor importante en el rendimiento general de DB. Quiero decir, ¿cuántos porcentajes son 30 MB? Me lo pensaría dos veces antes de reducir efectivamente el efectivo, digamos, en un 30% –

9

Tengo solo 6 años de retraso pero quizás pueda ayudar a alguien más.

Aquí hay algunas pautas que yo usaría:

  • Si existe la posibilidad de que los datos no caben en el futuro, entonces utilizar el mayor tipo int.
  • Si la variable se usa como un campo struct/class, de manera predeterminada se rellenará para ocupar los 32 bits completos de todos modos, por lo que usar byte/int16 no guardará la memoria.
  • Si la variable tiene una vida corta, entonces (como dentro de una función), los tipos de datos más pequeños no ayudarán mucho.
  • "byte" o "char" a veces puede describir mejor los datos y puede hacer una verificación de tiempo de compilación para asegurarse de que no se le asignen valores mayores por accidente. p.ej. Si almacena el día del mes (1-31) usando un byte y trata de asignarle 1000, se producirá un error.
  • Si la variable se usa en una matriz de aproximadamente 100 o más, usaría el tipo de datos más pequeño siempre que tenga sentido.
  • las matrices byte e int16 no son tan seguras para hilos como int (una primitiva).

Un tema que nadie mencionó es el limitado caché de la CPU.Los programas más pequeños se ejecutan más rápido que los más grandes porque la CPU puede acomodar más del programa en las cachés L1/L2/L3 más rápidas.

Utilizando el tipo int puede resultar en un menor número de instrucciones de la CPU sin embargo, también obligará a un mayor porcentaje de la memoria de datos que no caben en la caché de la CPU. Las instrucciones son baratas de ejecutar. Los núcleos de CPU modernos pueden ejecutar de 3 a 7 instrucciones por ciclo de reloj; sin embargo, una sola falta de caché por otro lado puede costar de 1000 a 2000 ciclos de reloj porque tiene que llegar hasta la RAM.

Cuando la memoria se conserva también resulta en el resto de la aplicación que realiza mejor, ya que no es expulsado de la caché.

Hice una prueba rápida con suma acceder a datos aleatorios en orden aleatorio utilizando tanto una matriz de bytes y una serie int.

const int SIZE = 10000000, LOOPS = 80000; 
byte[] array = Enumerable.Repeat(0, SIZE).Select(i => (byte)r.Next(10)).ToArray(); 
int[] visitOrder = Enumerable.Repeat(0, LOOPS).Select(i => r.Next(SIZE)).ToArray(); 

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); 
sw.Start(); 
int sum = 0; 
foreach (int v in visitOrder) 
    sum += array[v]; 
sw.Stop(); 

Estos son los resultados en el tiempo (garrapatas): (x86, modo de liberación, sin depurador, .NET 4.5, i7-3930K) (más pequeño es mejor)

________________ Array Size __________________ 
     10 100 1K 10K 100K 1M 10M 
byte: 549 559 552 552 568 632 3041 
int : 549 566 552 562 590 1803 4206 
  • acceso 1M ¡los elementos que usaban byte aleatoriamente en mi CPU tenían un aumento del 285% en el rendimiento!
  • Cualquier cosa por debajo de 10,000 fue apenas perceptible.
  • int nunca fue más rápido que el byte para esta prueba de suma básica.
  • Estos valores serán muy diferentes con diferentes CPU con diferentes tamaños de caché.

Una nota final: a veces miro el marco de .NET ahora de código abierto para ver lo que hacen los expertos de Microsoft. El framework .NET usa byte/int16 sorprendentemente poco. No pude encontrar ninguno en realidad.

+0

Wow este sitio ha estado aquí 6 años ... – Sameer

Cuestiones relacionadas