2010-02-11 18 views
10

¿Es mejor si hago esto:Si las declaraciones dentro o fuera de los bucles?

foreach my $item (@array) { 
    if ($bool) { 
    .. code .. 
    } 
    else { 
    .. code .. 
    } 
} 

o

if ($bool) { 
    foreach my $item (@array) { 
    } 
} 
else { 
    foreach my $item (@array) { 
    } 
} 
+4

¿Cambia $ bool por algo en cualquiera de los bucles? –

+0

$ bool es una variable estática que no cambia. – Timmy

+1

No hagas un 'si else' para cada iteración del ciclo' foreach'. El segundo ejemplo es definitivamente el camino a seguir. – JohnB

Respuesta

18

Dejo premature optimization a un lado.

"La optimización prematura es la raíz de todos los males" - Donald Knuth

Hay que ir para mantenimiento en primer lugar. Agrúpelos de la manera que tenga más sentido teniendo en cuenta la estructura lógica del código (como agrupar declaraciones relacionadas entre sí).

Si luego determina que el rendimiento es un problema, intente medir con algo así como un generador de perfiles para ver dónde están los cuellos de botella. Lo más probable es que no esté allí. De código completo 2:

Barry Boehm informa que el 20 por ciento de rutinas de un programa consumen el 80 por ciento de su tiempo de ejecución. En su artículo clásico "Un estudio empírico de Fortran Programs", Donald Knuth encontró que menos del cuatro por ciento de un programa generalmente representa más de el 50 por ciento de su tiempo de ejecución.

No debemos tratar de adivinar dónde optimizar antes de que sea necesario, ya que la mayoría de nosotros somos realmente malos para adivinar dónde está esa porción lenta de nuestro código. Los programadores que optimizan a medida que avanzan también gastan aproximadamente el 96% de su tiempo optimizando el código que no necesita optimizarse. Otra cosa a tener en cuenta es que la sintonización de código (como en este ejemplo) considera un compromiso entre la legibilidad y facilidad de mantenimiento para la prestación del servicio:

Centrándose en la optimización durante el desarrollo inicial resta valor a lograr otros objetivos del programa. Los desarrolladores se sumergen en el análisis de algoritmo y los debates arcanos que al final no aportan mucho valor al usuario. Las preocupaciones como corrección, ocultamiento de información y legibilidad se convierten en objetivos secundarios, aunque el rendimiento es más fácil de mejorar más tarde que estas otras preocupaciones. El rendimiento post hoc generalmente afecta a menos de cinco por ciento del código de un programa. ¿Podría regresar y realizar el trabajo de rendimiento en el cinco por ciento del código o el trabajo de legibilidad en el 100 por ciento?

No estoy diciendo que no optimizar, pero código Optimizar sólo en el extremo, cuando se tiene el lujo de la gran imagen y herramientas para señalarle en la dirección correcta.

EXTRA: Para responder a la cuestión de la representación en sí misma, sin embargo:

Este [ "unswitching" el código] es bueno para alrededor de un 20 por ciento de ahorro de tiempo:

Language  Straight Time Code-Tuned Time Time Savings 
C++    2.81    2.27    19%  
Java   3.97    3.12    21% 
Visual Basic 2.78    2.77    <1% 
Python   8.14    5.87    28% 

Un peligro distinto de este caso es que los dos bucles deben mantenerse en paralelo. [...] debe recordar cambiar el código en ambos lugares, lo cual es una molestia para usted y un dolor de cabeza de mantenimiento para cualquier otra persona que tenga que trabajar con el código.

Este ejemplo también ilustra un desafío clave en el ajuste de código: el efecto de cualquier ajuste de código específico no es predecible. El ajuste del código produjo mejoras significativas en tres de los cuatro idiomas, pero no en Visual Basic. Para realizar esta optimización específica de en esta versión específica de Visual Basic se produciría un código menos sostenible sin ninguna ganancia de compensación en el rendimiento. La lección general es que debe medir el efecto de cada optimización específica para asegurarse de su efecto - no hay excepciones .

Compruebe this other pregunta aquí en SO. Y this de la primera edición de Code Complete.

+7

No sé si siempre es una optimización prematura considerar los impactos en el rendimiento al escribir el código. Estoy de acuerdo en que en este caso podría ser insignificante, pero no siempre estoy de acuerdo con la declaración general de "optimización prematura". –

+4

@Andy: Bueno, en términos de elegir los algoritmos adecuados, etc., entonces sí, debe saber cuáles elegir para no terminar pesimizando seriamente su programa. Pero, en general, después de escribir el programa de la manera más clara posible (posiblemente haciendo refactorizaciones que podrían eliminar cualquier optimización prematura realizada), su perfilador hará un muy buen trabajo al decirle qué necesita solucionar en ese momento. –

+4

Pensar es bueno. Pensar en el rendimiento es bueno. Pero si su compilador no genera código idéntico para construcciones semánticamente idénticas, entonces es hora de arreglar su compilador. No micro-optimice sus aplicaciones para evitar errores de implementación de lenguaje, eso está funcionando en el nivel incorrecto de abstracción. – jrockway

3

te sugieren tanto tiempo y ver por sí mismo, pero no esperan que la diferencia sea enorme.

5

Si está optimizando la velocidad, la segunda (bucles foreach dentro de las ramas if) debería ser más rápida, ya que no hará la prueba en cada iteración de bucle.

+0

Debe escribir los programas y probarlos usted mismo. :-P Las pruebas de tiempo que he hecho sugieren que la diferencia es insignificante. –

+0

@Chris Jester-Young: De acuerdo, lo hice. Mi código inicializó una matriz de elementos de 1 millón y luego pasó por encima escribiendo el elemento en un archivo. El segundo método (bucles dentro del if) fue consistentemente más rápido y varió entre .3 segundos y 1.6 segundos, con un promedio de .7 segundos (de alrededor de 17 segundos por ejecución), con un promedio de aproximadamente 4% de mejoría. De acuerdo, no es grande, pero si es importante o no, dependerá de las circunstancias. – GreenMatt

+0

En mi libro, 0,7 segundos de diferencia de 17 segundos _es_ insignificante, pero como dices, supongo que depende del contexto. :-) –

7

El segundo será más rápido ya que muchas menos comparaciones. - La comparación está fuera del bucle en lugar de dentro.

Y dado que la variable de comparación es un bucle invariante, me sorprendería que no fuera también una codificación más clara.

diferencia de velocidad real (hora del reloj) depende del tamaño de la matriz

2

Simplemente evaluar una variable booleana como hemos hecho aquí, estos son más o menos equivalentes. Sin embargo, si la variable fuera reemplazada por una expresión complicada que tomó mucho tiempo evaluar, el segundo ejemplo sería mejor porque solo se evaluaría una vez.

+2

o podría establecer $ bool en el valor de la expresión complicada :) – ysth

+0

Cierto, cierto. Eso sería lo más natural de hacer. –

4

Todo el mundo parece atascado en el problema de rendimiento.

Casi siempre es mejor no tener que repetir el código. Es decir, escribir lo mismo más de una vez debería ser doloroso para usted. Como no ha dicho nada sobre el código en cada una, supongo que quiere hacer cosas diferentes en cada caso. Mi preferencia es separar los detalles de la iteración del procesamiento particular.

my $sub_ref = $bool ? make_true_function() : make_false_function(); 

foreach my $element (@array) { 
     $sub_ref->($element); 
     } 

sub make_true_function { sub { ... } } 
sub make_false_function { sub { ... } } 

Eso puede perder un poco en el rendimiento, pero es mucho más fácil de ver porque es un código menos enredado. Al foreach no le importa nada la ramificación ni la forma en que tomó su decisión. Esto funciona bien cuando quieres tener más sucursales también. Mientras lo correcto aparezca en $sub_ref, no cambiará el código de iteración.

Cuestiones relacionadas