2009-04-20 17 views
274

Duplicar posible:
Is there any significant difference between using if/else and switch-case in C#?¿Hay "else if" más rápido que "switch() case"?

soy un chico Pascal ex, actualmente el aprendizaje de C#. Mi pregunta es la siguiente:

¿El código siguiente es más rápido que hacer un cambio?

int a = 5; 

if (a == 1) 
{ 
    .... 
} 
else if(a == 2) 
{ 
    .... 
} 
else if(a == 3) 
{ 
    .... 
} 
else if(a == 4) 
{ 
    .... 
} 
else 
    .... 

y el interruptor:

int a = 5; 

switch(a) 
{ 
    case 1: 
     ... 
     break; 

    case 2: 
     ... 
     break; 

    case 3: 
     ... 
     break; 

    case 4: 
     ... 
     break; 

    default: 
     ... 
     break; 


} 

Cuál es más rápido?

Lo estoy preguntando, porque mi programa tiene una estructura similar (muchas, muchas declaraciones "else if"). ¿Debo convertirlos en interruptores?

+65

Me siento obligado a notar que puede estar utilizando poco el polimorfismo en sus diseños si su código tiene muchas de estas estructuras. –

+4

Vea http://stackoverflow.com/questions/445067/if-vs-switch-speed –

+0

El cambio es más rápido, pero a menos que esté hiper optimizando un circuito cerrado, no significa nada. ¿Qué es 37 nanosegundos frente a 42 nanosegundos (números compuestos)? –

Respuesta

466

Por solo algunos artículos, la diferencia es pequeña. Si tiene muchos elementos, definitivamente debe usar un interruptor.

Si un interruptor contiene más de cinco elementos, se implementa utilizando una tabla de búsqueda o una lista de hash. Esto significa que todos los artículos obtienen el mismo tiempo de acceso, en comparación con una lista de si: s donde el último elemento toma mucho más tiempo para llegar ya que tiene que evaluar cada condición previa primero.

+75

Es cierto, pero con una cadena if-else-if puede ordenar las condiciones según la probabilidad de que sean ciertas. –

+58

Sí, pero los primeros 4-5 casos tienen que atrapar muy cerca del 100% de las ocurrencias para compensar las más lentas. – Guffa

+21

¿No deberían la mayoría de los compiladores modernos optimizar el if/else profundo si/else if/else si los puntos de decisión son una tabla de conmutación/salto? Que es decir; esto no debería importar, el compilador va a optimizarlo, ¿por qué no solo escribir el código más legible? –

5

No debe ser difícil de probar, cree una función que cambie entre 5 números, eche un rand (1,5) en esa función y buclee eso varias veces mientras lo sincroniza.

3

Técnicamente, producen exactamente el mismo resultado, por lo que deberían ser optimizables de la misma manera. Sin embargo, hay más posibilidades de que el compilador optimice la caja del conmutador con una tabla de salto que el ifs.

Estoy hablando del caso general aquí. Para 5 entradas, la cantidad promedio de pruebas realizadas para el ifs debe ser menor a 2.5, suponiendo que ordene las condiciones por frecuencia. Difícilmente es un cuello de botella para escribir sobre casa a menos que esté en un círculo muy cerrado.

5

El cambio es generalmente más rápido que una larga lista de ifs porque el compilador puede generar una tabla de salto. Mientras más larga sea la lista, mejor será una declaración de cambio sobre una serie de declaraciones if.

+2

No está permitido que la tabla de salto aplique (IIRC) para valores contiguos. No es raro que el compilador emita una combinación de tablas de salto y breq para opciones complejas no contiguas. –

19

Creyendo this performance evaluation, la caja del interruptor es más rápida.

Esta es la conclusión:

Los resultados muestran que la instrucción switch es más rápido de ejecutar que la si-else-if escalera. Esto se debe a la capacidad del compilador de optimizar la declaración de cambio. En el caso de la escalera if-else-if, el código debe procesar cada sentencia if en el orden determinado por el programador. Sin embargo, debido a que cada caso dentro de una declaración de cambio no se basa en casos anteriores, el compilador puede volver a ordenar las pruebas de tal manera que proporcione la ejecución más rápida.

3

switch generalmente se traduce en una tabla de búsqueda por el compilador, si es posible. Entonces, la búsqueda de un caso arbitrario es O (1), en lugar de hacer algunas comparaciones de casos antes de encontrar el que desea.

Por lo tanto, en muchos casos una cadena if/else if será más lenta.Dependiendo de la frecuencia con la que se golpean sus cajas, eso puede no hacer ninguna diferencia, sin embargo.

2

Respuesta corta: sentencia switch es más rápido

La sentencia if se necesitan dos comparaciones (cuando se ejecuta el código de ejemplo), en promedio, para llegar a la cláusula correcta.

La sentencia switch el número medio de comparaciones será uno independientemente del número de casos diferentes que tiene. El compilador/VM habrá creado una "tabla de búsqueda" de opciones posibles en tiempo de compilación.

¿Pueden las máquinas virtuales optimizar la instrucción if de forma similar si ejecuta este código a menudo?

11

Otra cosa a considerar: ¿es esto realmente el cuello de botella de su aplicación? Existen casos extremadamente raros cuando realmente se requiere una optimización de este tipo. La mayoría de las veces puede obtener aceleraciones mucho mejores repensando sus algoritmos y estructuras de datos.

4

Mucho más importante que los beneficios de rendimiento del interruptor (que son relativamente pequeños, pero vale la pena señalar) son los problemas de legibilidad.

mi parte, encontrar una instrucción switch muy claro en la intención y el espacio en blanco puro, en comparación con las cadenas de IFS.

147

¿Por qué te importa?

99.99% del tiempo, no debería importarle.

Este tipo de micro-optimizaciones es poco probable que afecte el rendimiento de su código.

Además, si se necesita para cuidar, entonces usted debe hacer perfiles de rendimiento en su código. En cuyo caso, descubrir la diferencia de rendimiento entre una caja de conmutación y un bloque if-else sería trivial.

Edit: En aras de la claridad: implemente el diseño que sea más claro y más fácil de mantener. En general, cuando se enfrenta a un gran switch-case o bloque if-else, la solución es usar polimorfismo. Encuentra el comportamiento que está cambiando y encapsularlo. He tenido que lidiar con un código de caja de interruptor enorme y feo como este antes y, en general, no es tan difícil de simplificar. Pero tan satisfactorio.

+45

Creo que el 100% del tiempo, no deberías preocuparte. – Naveen

+78

Absolutamente no estoy de acuerdo. Definitivamente siempre debería preocuparse, no tanto por el rendimiento, sino también por la legibilidad y la facilidad de mantenimiento del código. Y, como lo mencionaron otros, podría pensar en una mejor utilización del polimorfismo. –

+5

Oh, estoy de acuerdo en que siempre debería preocuparse por la legibilidad y el mantenimiento. La forma correcta de reescribir un gran interruptor/bloque de caja es probablemente el polimorfismo (que, dicho sea de paso, es probablemente un poco más lento, pero no debería importarle). La macro-optimización (buen diseño) siempre es mejor que la micro-optimización (declaraciones más rápidas). – Wedge

1

Desde la declaración switch expresa la misma intención que la cadena de if/else pero de una manera más restringida, formal, su primera suposición debe ser que el compilador será capaz de optimizar mejor, ya que se puede extraer más conclusiones sobre las condiciones colocadas en su código (es decir, solo un estado puede ser cierto, el valor que se compara es un tipo primitivo, etc.). Esta es una verdad general bastante segura cuando se comparan dos estructuras de lenguaje similares para el rendimiento del tiempo de ejecución.

4

No estoy seguro, pero creo que la velocidad de uno u otro cambia dependiendo del lenguaje de programación que esté usando.

Por lo general, prefiero usar el interruptor.De esa forma, el código es simple de leer.