¿Es importante la microoptimización al codificar?


178

Hace poco hice una pregunta sobre Stack Overflow para descubrir por qué isset () era más rápido que strlen () en PHP . Esto planteó preguntas sobre la importancia del código legible y si valía la pena considerar las mejoras de rendimiento de microsegundos en el código.

Mi padre es un programador retirado y le mostré las respuestas. Estaba absolutamente seguro de que si un codificador no considera el rendimiento en su código, incluso a nivel micro, no son buenos programadores.

No estoy tan seguro: ¿quizás el aumento en la potencia de cómputo significa que ya no tenemos que considerar este tipo de mejoras de micro rendimiento? ¿Quizás este tipo de consideración depende de las personas que escriben el código de idioma real? (de PHP en el caso anterior).

Los factores ambientales podrían ser importantes: Internet consume el 10% de la energía mundial. Me pregunto cuán derrochador son unos pocos microsegundos de código cuando se replican billones de veces en millones de sitios web.

Me gustaría saber las respuestas preferiblemente basadas en hechos sobre programación.

¿Es importante la microoptimización al codificar?

Mi resumen personal de 25 respuestas, gracias a todos.

A veces necesitamos preocuparnos realmente por las micro optimizaciones, pero solo en circunstancias muy raras. La fiabilidad y la legibilidad son mucho más importantes en la mayoría de los casos. Sin embargo, considerar la micro-optimización de vez en cuando no hace daño. Una comprensión básica puede ayudarnos a no tomar malas decisiones obvias al codificar como

if (expensiveFunction() || counter < X)

Debiera ser

if (counter < X || expensiveFunction())

( Ejemplo de @ zidarsk8 ) Esta podría ser una función económica y, por lo tanto, cambiar el código sería una microoptimización. Pero, con una comprensión básica, no tendría que hacerlo, porque lo escribiría correctamente en primer lugar.


123
El consejo de tu padre no está actualizado . No preguntaría cuánto mejora el rendimiento. Preguntaría dónde está el cuello de botella. No importa si mejora el rendimiento de una sección de código si no hace una diferencia general, su enlace más lento determinará la velocidad. En PHP esto está escribiendo a la red (a menos que pueda probar que IE mide lo contrario); lo que se traduce en escribir código más legible es más importante.
Martin York

61
Si se considera la palabra clave, no está equivocado. Tienes que tener alguna pista al respecto.
JeffO

37
Me entristece porque aún no se ha mencionado la famosa cita de optimización prematura : "Los programadores pierden enormes cantidades de tiempo pensando o preocupándose por la velocidad de las partes no críticas de sus programas, y estos intentos de eficiencia realmente tienen un fuerte negativo impacto cuando se consideran la depuración y el mantenimiento. Deberíamos olvidarnos de las pequeñas eficiencias, digamos alrededor del 97% del tiempo: la optimización prematura es la raíz de todo mal . Sin embargo, no debemos dejar pasar nuestras oportunidades en ese crítico 3% ".
Tamara Wijsman

13
¿Puede proporcionar una fuente de "10% de la energía mundial"?
Michael Easter

17
coder does not consider performance in their code even at the micro level, they are not good programmersEs muy diferente de la micro-optimización. Es solo una buena codificación.
woliveirajr

Respuestas:


90

Estoy de acuerdo y en desacuerdo con tu padre. Se debe pensar en el rendimiento temprano, pero solo se debe pensar en la micro-optimización temprano si realmente sabe que se pasará un alto porcentaje de tiempo en pequeñas secciones de código vinculadas a la CPU.

El problema con la microoptimización es que generalmente se realiza sin tener ningún concepto de cómo los programas realmente pasan más tiempo del necesario.

Este conocimiento proviene de la experiencia en el ajuste del rendimiento, como en este ejemplo , en el que un programa aparentemente sencillo, sin ineficiencias evidentes, se lleva a cabo a través de una serie de pasos de diagnóstico y aceleración, hasta que es 43 veces más rápido que al principio.

Lo que muestra es que realmente no puedes adivinar o intuir dónde estarán los problemas. Si realiza un diagnóstico, que en mi caso es una pausa aleatoria , las líneas de código responsables de una fracción significativa de tiempo se exponen preferentemente. Si observa esos, puede encontrar código sustituto y, por lo tanto, reducir el tiempo total en aproximadamente esa fracción.

Otras cosas que no arregló aún toman tanto tiempo como lo hicieron antes, pero dado que el tiempo general se ha reducido, esas cosas ahora toman una fracción mayor, por lo que si lo vuelve a hacer, esa fracción también se puede eliminar. Si sigue haciendo esto en varias iteraciones, así es como puede obtener aceleraciones masivas , sin necesariamente haber realizado ninguna microoptimización .

Después de ese tipo de experiencia, cuando aborda nuevos problemas de programación, llega a reconocer los enfoques de diseño que inicialmente conducen a tales ineficiencias. En mi experiencia, proviene del diseño excesivo de la estructura de datos, la estructura de datos no normalizada, la dependencia masiva de las notificaciones, ese tipo de cosas.


120

La microoptimización solo es importante si los números lo dicen.

Los requisitos con los que está desarrollando deben tener alguna especificación de los datos de rendimiento, si el rendimiento es un problema para el cliente o usuario. A medida que desarrolla software, debe probar el rendimiento de su sistema contra estos requisitos. Si no cumple con los requisitos de rendimiento, debe perfilar su base de código y optimizar según sea necesario para alcanzar los requisitos de rendimiento. Una vez que esté dentro del rendimiento mínimo requerido, no es necesario exprimir más el rendimiento del sistema, especialmente si va a comprometer la legibilidad y la facilidad de mantenimiento del código (en mi experiencia, el código altamente optimizado es menos legible y mantenible, pero no siempre). Si puede obtener ganancias de rendimiento adicionales sin degradar los otros atributos de calidad del sistema,

Sin embargo, hay casos en los que el rendimiento es de suma importancia. Estoy pensando principalmente en sistemas en tiempo real y sistemas integrados. En los sistemas en tiempo real, cambiar el orden de las operaciones puede tener un efecto enorme en el cumplimiento de los plazos estrictos que se requieren para una operación adecuada, tal vez incluso influya en los resultados de los cálculos. En los sistemas integrados, normalmente tiene memoria limitada, potencia de CPU y potencia (como en la batería), por lo que debe reducir el tamaño de sus archivos binarios y la cantidad de cálculos para maximizar la vida útil del sistema.


Por otro lado, si hay un problema entre el uso de una función más lenta frente a una más rápida, no hay razón para usar la función más lenta, como aquí en caso de isset.
Mavrik

77
@Mavrik Eso es cierto. Si tiene dos funciones, X e Y, e Y es más rápido que X (al menos para sus condiciones particulares), no hay razón para no usar Y, si el código sigue siendo legible y fácil de mantener. Pero si no sabe acerca de Y y necesita refactorizar el código para usar Y en lugar de X, y el rendimiento (de ese segmento de código) no es un problema, entonces no hay razón para hacer ese cambio. Se trata de compensaciones: rendimiento, tiempo, costo, esfuerzo, legibilidad / mantenibilidad, etc.
Thomas Owens

2
Estoy totalmente de acuerdo, solo quería hacer este punto cuando se trata de la microoptimización: si no le cuesta nada en términos de legibilidad / tiempo, hágalo. De lo contrario no lo hagas.
Mavrik

El código +1 altamente optimizado es menos legible y mantenible ... pero no siempre.
Boz

Más casos en los que el rendimiento es importante: (1) juegos; (2) grandes cantidades de datos; (3) sitio web de alto tráfico; (4) capacidad de respuesta de una IU altamente compleja; (5) servicio que se supone que se ejecuta en segundo plano, como la detección de virus; (6) finanzas; (7) teléfono inteligente; y así. No se limita a casos esotéricos como RTS y sistemas integrados.
Rex Kerr

103

Cada vez que alguien pregunta acerca de la optimización , recuerdo la cita de Michael A. Jackson

La primera regla de optimización del programa: no lo hagas.

La segunda regla de optimización de programas (¡solo para expertos!): No lo hagas todavía .

Cita de Wikipedia corregida para inglés británico. * 8 ')

Implícito en la segunda regla es perfilar su código y solo pasar tiempo optimizando cosas que marcarán la diferencia.

Al programar en asamblea, la afirmación de su padre era correcta. Pero eso está mucho más cerca del metal de lo que la mayoría de la gente programa en estos días. Hoy, incluso intentar optimizarse (sin perfilar) puede hacer que su código se ejecute más lentamente que si hubiera hecho algo de la manera más común, ya que es más probable que los compiladores JIT modernos optimicen la forma común .

Incluso en C tienes que ser bastante bueno en la optimización para saber más sobre cómo optimizar una sección de código que el compilador.

Si no está familiarizado con gran parte de lo que Ulrich Drepper habla en su excelente artículo Lo que todo programador debe saber sobre la memoria , entonces es probable que sea un perdedor incluso tratando de optimizarlo. Sin embargo, al contrario del título de los documentos (que en realidad es un homenaje a lo igualmente fantástico de David Goldberg Lo que todo informático debe saber sobre la aritmética de punto flotante ) no tener este nivel de comprensión no necesariamente te impide ser un buen programador, solo un tipo diferente de programador.

isset()vs. strlen()en PHP

No conozco PHP, por lo que realmente no es obvio lo isset()que debe hacer. Puedo inferirlo del contexto, pero esto significa que será igualmente oscuro para los programadores PHP novatos e incluso podría causar que los programadores más experimentados tomen el doble. Este es el tipo de uso idiomático de un lenguaje que puede hacer que el mantenimiento sea una pesadilla.

No solo eso, sino que no hay garantía de que isset()siempre sea más eficiente, solo porque ahora es más eficiente. Una optimización ahora podría no ser una optimización el próximo año, o en 10 años. Las CPU, los sistemas, los compiladores mejoran y cambian con el tiempo. Si el rendimiento de PHP strlen()es un problema, PHP podría modificarse en el futuro, entonces todas las optimizaciones de isset () pueden necesitar eliminarse para optimizar el código una vez más.

Cada optimización tiene el potencial de convertirse en una futura anti-optimización , por lo que debe considerarse un posible olor a código, que debe mantenerse al mínimo.

Un ejemplo de experiencia personal.

Como ejemplo de tal anti-optimización , una vez tuve que desinfectar una enorme base de código llena con el código del formulario if x==0 z=0 else z=x*yporque alguien había asumido que una multiplicación de coma flotante siempre iba a ser más costosa que una rama. En la arquitectura de destino original, esta optimización hizo que el código se ejecutara un orden de magnitud más rápido, pero los tiempos cambian.

Cuando intentamos usar este código en una CPU más moderna que estaba altamente canalizada, el rendimiento fue terriblemente malo: cada una de estas declaraciones causa un vaciado de tubería. Simplificando todas estas líneas de código para z=x*yhacer que el programa ejecute un orden de magnitud más rápido en la nueva arquitectura, restaurando el rendimiento perdido por la anti-optimización .

Los problemas que normalmente tenemos que optimizar para hoy son muy diferentes a los que tuvimos que optimizar hace 20 o incluso 10 años.

Luego nos preocupamos por hacer la mayor cantidad de trabajo por ciclo de reloj, ahora es más probable que nos preocupemos por los enjuagues de tuberías, las predicciones erróneas de ramas y las fallas de caché a nivel de CPU, pero las cerraduras y la comunicación entre procesos se están volviendo mucho más significativas a medida que avanzamos hacia múltiples arquitecturas de proceso y multiprocesador. El artículo de Drepper realmente puede ayudar a comprender muchos de estos problemas.


3
La eliminación de la tubería y la pérdida de caché es lo que desea evitar: D Tienen costos horribles. pero solo en partes del código que las ejecutan muchas muchas muchas muchas muchas veces.
deadalnix

77
Una cosa que agregaría es que los compiladores han recorrido un largo camino y optimizarán muchas cosas para usted. AFAIK, optimizan mejor el código limpio y legible que las cosas difíciles.
Becuzz

3
+1 por proporcionar un ejemplo real de una microoptimización que desperdiciaba tiempo y revelaba que Michael Jackson era un programador.
Boz

1
+1 Por el ejemplo. Ilustra perfectamente por qué debería dejar transformaciones triviales en el compilador.
back2dos

1
@Rex Kerr> en el ejemplo, el costo proviene de la ramificación, lo que causa la descarga de la tubería de la CPU. La multiplicación de punto flotante también es costosa. Lo que es más económico depende en gran medida de la FPU y la longitud de la tubería de la CPU que ejecuta el código. No me sorprendería que este código se ejecute más rápido en CPU más antiguas que tienen una tubería más corta y menos FPU eficiente que la CPU actual.
deadalnix

84
  1. Escribir código, que sea limpio, conciso, simple y autoexplicativo.
  2. Realice pruebas de rendimiento para identificar cuellos de botella.
  3. Optimizar secciones críticas.

Como regla general: el 95% de su código se ejecuta el 5% del tiempo. No tiene sentido optimizar antes de perfilar / comparar su código y ver cuáles son los 5% que se ejecutan el 95% del tiempo.

Cada idiota puede hacer micro-optimización y cualquier compilador / tiempo de ejecución decente lo hará por usted.
Optimizar un buen código es trivial. Escribir código optimizado e intentar que sea bueno después de eso es tedioso en el mejor de los casos e insostenible en el peor.

Si en serio se preocupa por su rendimiento, entonces no usar PHP para el rendimiento del código crítico. Encuentre los cuellos de botella y vuelva a escribirlos con extensiones C. Incluso la micro optimización de su código PHP más allá del punto de ofuscación no le dará tanta velocidad.

Personalmente, me gustaba mucho la microoptimización cuando comencé a programar. Porque es obvio. Porque te recompensa rápidamente. Porque no tienes que tomar decisiones importantes. Es el medio perfecto de procrastinación. Le permite escapar de las partes realmente importantes del desarrollo de software: el diseño de sistemas escalables, flexibles, extensibles y robustos.


2
La mejor respuesta para mí fue encontrada, notablemente, en la Guía del desarrollador de Bugzilla: "Si estás tratando de ser inteligente en lugar de ser legible, entonces tal vez estás tratando de hacer las cosas" más rápido ". Si es así, solo recuerda : no resuelva un problema antes de saber que existe. Si no sabe (mediante pruebas reales y detalladas) que su código es lento, no se preocupe por hacerlo "más rápido". Esto no se limita a optimización: muchos programadores resuelven constantemente problemas que nadie ha experimentado nunca. No hagas eso ". bugzilla.org/docs/developer.html#general
Marco

77
En general, estoy de acuerdo, excepto por una línea, afirmo que "todo idiota piensa que puede micro-optimizar" ...;)
Nim

@Nim: Punto tomado;)
back2dos

26

Estoy de acuerdo con su padre: "Si un codificador no considera el rendimiento en su código incluso a nivel micro, no son buenos programadores". La clave es "considerar el rendimiento". Eso no es equivalente a "hacer micro optimizaciones en cada paso".

Estoy de acuerdo con la mayoría de los otros comentarios: lo que solía hacer que los programas de C sean más rápidos puede que no lo haga hoy, pero hay otras cosas serias que considerar: ¿Debo usar C o C ++? Las clases con operadores simples sobrecargados pueden matar el rendimiento si los usa mucho. ¿Eso importa? Depende de su aplicación, pero si ni siquiera lo CONSIDERA, no es un muy buen programador. Algunas personas podrían considerarlo durante unos 2 milisegundos y descartarlo, pero creo que demasiados literalmente ni siquiera lo consideran.

La realidad es que con la optimización, el código puede ser más difícil de leer. El código tardará más en escribir. El código estará en algún lugar entre un poco más rápido y un orden de magnitud más rápido (eso es raro). Sus clientes probablemente no notarán la diferencia.

Otra realidad es que a la gente le gusta reutilizar el código, y donde termina puede ser muy diferente de cuando lo escribió. De repente, a las personas les puede importar.

Como ejemplo, supongamos que escribió algo como Angry Birds en una PC o para una consola de juegos. No tuvo en cuenta la optimización en su sistema de física y su sistema de gráficos, porque los núcleos duales de 2.5 GHz son básicamente el mínimo en estos días, y su juego funciona lo suficientemente bien. Luego aparecen los teléfonos inteligentes y quieres portarlos. Oh maldita sea, ¿un núcleo ARM de 600 MHz ?

Piense en un sitio web: algo lanzado en un fin de semana como Hot or Not . Utiliza cualquier base de datos que sea útil, escribe todo con un rápido desarrollo en mente, inicia el envío enviando una URL a tus amigos. Tres meses después, su servidor se está muriendo por sobrecarga y no hay nada que pueda hacer para escalar. Pasa todo el tiempo. Los sitios web más grandes tienen facturas de energía medidas en cientos de kilovatios o incluso megavatios. Piense en eso, hay megavatios que se guardarán a través de la optimización del código.

Como dijo tu padre, al menos debes considerarlo . La mayoría de la gente ni siquiera sabe cuánto rendimiento hay en la mesa y pasa desapercibido con un comentario rápido sobre "optimización prematura" y "no lo hagas". Estos no son buenos programadores.

Esta no es una opinión popular en estos sitios. Adiós puntos de reputación ...


3
Claro, debe considerarlo (en la parte posterior de su cabeza) y generalmente rechazarlo, a menos que se demuestre que vale la pena. Debe tener en cuenta que las optimizaciones generalmente reducen la legibilidad del código y pueden aumentar el tiempo necesario para codificar y mantener en un factor de aproximadamente 10. Si el programa no requiere mucha CPU, a menudo no es necesario. Reconozca que su compilador generalmente es mucho mejor en optimización que usted, y que muchas de sus optimizaciones realmente afectarán el rendimiento. Si no vale la pena su tiempo para probar sus optimizaciones y su perfil, no vale la pena su tiempo para optimizar.
dr jimbob

3
Su ejemplo Angry Birds muestra exactamente por qué usted debe no optimizar prematuramente. Al portar desde el escritorio a la consola a los dispositivos móviles, se trata (al menos) de tres tipos muy diferentes de hardware y la optimización para uno puede dañar en lugar de ayudar en otro. Peor aún, la optimización hará que el código sea más difícil de entender, por lo tanto, más difícil de portar. Claro, elija algoritmos eficientes desde el principio, pero guarde la microoptimización para la fase de ajuste del rendimiento cuando los datos reales le indiquen dónde está el problema en cada plataforma.
Caleb

@Caleb: El ejemplo de Angry Birds ilustra por qué no optimizar para un hardware en particular. También ilustra cómo puede construir una aplicación completa sin molestarse en hacer optimizaciones más generales de "nivel C" y luego quemarse. En realidad no se quema, pero tiene problemas para ir más allá de su intención original.
phkahler

25

Primero tomemos su caso: PHP

  • No creo que PHP sea un tipo de lenguaje (tanto por su naturaleza como por su dominio principal de aplicación) que deba preocuparse por estas "microoptimizaciones". El código PHP está optimizado principalmente con el almacenamiento en caché de opcode
  • Los programas escritos en PHP no están vinculados a la CPU, en su mayoría están vinculados a E / S , por lo que estas optimizaciones no valdrán la pena de todos modos.
  • Cualquier cosa que DEBE optimizar probablemente debería colarse en una extensión C y luego cargarse dinámicamente en el tiempo de ejecución de PHP
  • Como puede ver, no obtenemos ningún incentivo al micro-optimizar nuestro código en PHP, por otro lado, si dedica ese tiempo a hacer que el código PHP sea más legible y mantenible, eso le pagará más dividendos.

En general,

No pasaría mucho tiempo "TOOOOO" optimizando mi código en un lenguaje dinámico como Python o Ruby , porque NO están diseñados para tareas de cálculo intensivo de números de CPU. Resuelven diferentes clases de problemas donde modelar una situación del mundo real de una manera elaborada (que es fácil de leer y mantener), lo que se llama expresividad , es más importante que la velocidad. Si la velocidad fuera la principal preocupación, no serían dinámicos en primer lugar.

Para los programas compilados (C ++, Java), la optimización es más crucial. Pero allí también, primero tienes que mirar la naturaleza / dominio / propósito del programa que estás escribiendo. También debe sopesar cuidadosamente el tiempo para micro-optimizar contra las ganancias de esa optimización. Si necesita aún más optimización, entonces también puede considerar ir un paso hacia abajo y codificar esas partes de su código en ensamblador.

Entonces, para responder a su pregunta original: "¿Es importante la microoptimización al codificar?" -- La respuesta es, depende --

  • ¿Qué tipo de cosas estás haciendo: dominio de aplicación, complejidad?
  • ¿Son REALMENTE importantes las mejoras de velocidad en microsegundos para su programa?
  • ¿Qué tipo de optimización será más provechosa? Puede que no siempre sea optimización de código, sino algo externo.
  • ¿Cuánta "bondad" (en términos de velocidad) está cosechando del tiempo que invierte en la micro optimización?
  • ¿Se pueden lograr mejores velocidades de otras maneras: cambiando el hardware, la RAM y el procesador, ejecutando código en paralelo o en un sistema distribuido?

La microoptimización (optimización del código para el caso) no solo lleva mucho tiempo, sino que "distorsiona" la legibilidad natural de su código, lo que lo hace pesado en mantenimiento. Siempre considérelo como un último recurso: siempre trate de optimizar toda la aplicación adoptando un mejor hardware y una mejor arquitectura que la optimización de archivos de código individuales.


18

Parece que hay muchas respuestas que dicen que la micro optimización es

todo sobre las compensaciones: rendimiento, tiempo, costo, esfuerzo, legibilidad / mantenimiento, etc.

Pero bueno, sé que hay algunas optimizaciones en las que no hay impacto de legibilidad, y me gusta hacerlas por diversión. Vi en algunas de mis tareas escolares (todas basadas en la velocidad), que siempre es bueno considerar la micro optimización al escribir declaraciones condicionales como:

if (counter < X && shouldDoThis()) // shouldDoThis() is an expensive function

siempre es mejor que

if (shouldDoThis() && counter < X ) 

Hay bastantes maneras de "acelerar" su código de esa manera y la diferencia suele ser insignificante (aunque no siempre), pero me siento mejor si lo escribo así.

No sé si alguien incluso considera esto como una optimización real, pero creo que un programador debería saber y considerar estas cosas al escribir su código.


2
Puede que no sea importante para este caso particular . Sin embargo, creo que es muy importante ser capaz de reconocer optimizaciones como estos para que cuando se hace la materia, que no tiene que gastar tiempo innecesario perfiles y optimizando después del hecho.
tskuzzy

44
Este es un ejemplo muy peligroso . Una optimización nunca debería cambiar el comportamiento . Incluso sugiriendo que cheap() && expensive()es una optimización de expensive () && cheap()invita a las personas a sustituir ciegamente una por la otra sin tener en cuenta el cambio semántico significativo que crea (en los idiomas donde &&está el operador de cortocircuito).
Mark Booth

55
Si las funciones no tienen efectos secundarios, son equivalentes y una es más rápida. Si tienen efectos secundarios, uno no debería estar escribiendo el código como este en primer lugar. Incluso diría que se debe hacer por costumbre, a menos que realmente cambie el comportamiento.
phkahler

3
@ MarkBooth Tengo que estar de acuerdo con phkahler aquí, ¡ninguna de estas funciones debería tener efectos secundarios! El orden de los condionos en una declaración if no debe tener un efecto en el resultado del programa. Mi ejemplo estaría mejor escrito como if (x<100 && isPrime(x)), solo para aclararlo.
zidarsk8

1
@ zidarsk8: si una optimización cambia cualquier cosa que no sea la velocidad de ejecución, entonces no es una optimización . Como programadores, a menudo tenemos que ser pragmáticos , y a veces eso significa que no podemos garantizar que todas las funciones utilizadas con un operador de cortocircuito sean puras, especialmente cuando nuestro código llama a bibliotecas de terceros sobre las que no tenemos control. En esa situación, debe tener cuidado de que no se aliente a los programadores inexpertos a introducir errores en nombre de la optimización .
Mark Booth

11

Al principio de mi carrera, declaraciones generales como "no micro-optimizar" me causaron mucha confusión. Todo es circunstancial; así, la razón por la cual la gente dice "mejor práctica" en lugar de "hacer esto".

La "mejor práctica" es la mejor opción teniendo en cuenta todas las circunstancias. Por ejemplo, LINQ y Entity Framework deben usarse en lugar de SQL en línea. En mi empresa estamos en SQL Server 2000 . SQL Server 2000 no es compatible con Entity Framework. Las mejores prácticas requieren:

  • Vender a mi jefe con la idea de comprar una nueva versión de SQL Server que significa varios miles de dólares.
  • Venta de desarrolladores con la idea de aprender nuevas tecnologías.

Sé por experiencia que esto no va a suceder. Entonces, podría dejar de fumar, estresarme sin fin o no seguir la mejor práctica.

Hay consideraciones políticas, técnicas y monetarias detrás de las decisiones que afectan el resultado general. Recuerda este hecho al tomar una decisión y elige tus batallas sabiamente.

" Para todo hay una temporada, un tiempo para cada actividad bajo el cielo " .


1
Por cierto, puede usar Dapper como una alternativa micro-ORM a SQL en línea.
Dan

2
LINQ and Entity Framework should be used in lieu of inline SQL- Hasta que realmente necesite SQL en línea para optimizar algo; el SQL que produce EF no siempre es óptimo.
Robert Harvey

1
fwiw, si su jefe está preocupado por los costos de licencia de SQL 2k8 (o cualquier otra cosa que pueda estar vigente), debe señalar que es lo suficientemente viejo como para aparecer en EOL MUY pronto (si aún no lo está)
warren

@warren: algunas empresas no tienen en cuenta estas cosas. Para algunos, si todavía "funciona", entonces no se actualizarán. Por trabajo, quiero decir que el servidor aún se ejecuta. Ya vemos una falta de apoyo con EF. Eso simplemente no es suficiente para convencerlos de gastar dinero.
P.Brian.Mackey

1
Para que lo sepas, puedes usar EF con SQL 2000. El diseñador no funciona, pero el marco de entidad real admite SQL 2000. Para evitar la limitación del diseñador, puedes crear una base de datos local en SQL 2008 Express con el mismo esquema como la base de datos sql 2000, apunte al diseñador para que genere todas las clases, luego vaya al archivo .edmx y cambie la versión de la base de datos de destino a 2000 y apunte la cadena de conexión a la base de datos de su servidor sql 2000. No es la mejor solución, pero si no puede actualizar, funciona.
Neil

8

Esto siempre es una compensación.

Primero, la industria informática se trata de dinero al final. Lo que debe hacer como desarrollador es generar valor para el cliente para que obtenga dinero (eso es una simplificación excesiva, pero el punto principal está aquí).

El tiempo del desarrollador cuesta dinero. La potencia de la máquina también cuesta dinero. Por lo general, este segundo costo es mucho más bajo que el primero. Por lo tanto, este es un capital para tener un código legible y un código que se pueda mantener, para que el desarrollador pueda pasar la mayor parte de su tiempo entregando valor.

La micro optimización puede, en algunos casos, ser importante. Pero generalmente implican un código menos legible o un código menos extensible (este no es el caso de su ejemplo vinculado, pero en general lo es). Esto costará en algún momento el tiempo del desarrollador. Esta vez es más costoso que la potencia de la máquina, esto es un desperdicio.

En segundo lugar, la microoptimización en un proyecto grande puede dificultar cada vez más el mantenimiento / evolución. El problema con eso es que, al evolucionar, ahora puede ser imposible realizar alguna otra optimización. Con una aplicación en evolución, generalmente terminará con una solución que es más lenta de lo que hubiera tenido sin hacer esas optimizaciones.

En tercer lugar, la optimización es a menudo irrelevante ya que la complejidad del algoritmo generalmente superará cualquier microoptimización que podría haber hecho si el conjunto de datos crece. Lamentablemente, como la micro-optimización hace que su código sea más difícil de mantener / evolucionar, esa optimización puede ser más difícil de hacer.

En algún momento, el valor está en esta optimización (piense en los programas críticos de latencia, como en los videojuegos o el piloto automático de un avión). Pero esto tiene que ser demostrado. Por lo general, su programa pasa la mayor parte del tiempo en una porción limitada de código. Independientemente de la microoptimización que haga, nunca obtendrá sus programas de manera mucho más rápida sin identificar el cuello de botella y trabajar en esta parte.

Hacer su pregunta como lo hizo demostró que no evaluó el problema en un programa real. En este caso, podrías haber hecho el truco y notar si era más rápido o no. Entonces preguntabas eso antes de tener algún problema. Aquí es donde está el problema. Estaba manejando el problema de la optimización de la manera incorrecta.

Dado que el mantenimiento y la evolución suelen ser más valiosos que la microoptimización, asegúrese de tener la interfaz correcta antes de realizar ninguna. Luego, si partes de su programa son lo suficientemente abstractas entre sí, puede micro-optimizar una sin estropear todo. Esto requiere que su interfaz se ejecute durante el tiempo suficiente para ser confiable.


"Siempre hay una compensación". Es cierto que la reducción de una variable aumentará la otra, si el programa está en la curva de compensación . En mi experiencia, la mayoría de los programas no están cerca de la curva de compensación, y tienen mucho espacio para reducir ambas variables.
Mike Dunlavey

El mantenimiento y la evolución de +1 son más valiosos que la microoptimización. ¿Aunque estoy seguro de que la industria informática es algo más que dinero? Por ejemplo, código abierto, educación, innovación, gobernanza, comunidad, etc. Estoy seguro de que se puede encontrar dinero en la raíz, pero eso es cierto para la mayoría de las cosas.
Boz

@Boz kay> Esto es parcialmente cierto. Primero, porque tu jefe y tu cliente no saben nada sobre estos y se preocupan por el dinero. Si desea promover algunas herramientas de código abierto, debe decirles cómo mejorará la marca de la empresa o cómo reducirá los costos de desarrollo. Además, hacer felices a los desarrolladores es una forma de obtener buenos desarrolladores en su empresa. Un buen desarrollador gana dinero (principalmente arroja calidad e innovación). Al final, el dinero es la clave. Y estoy escribiendo que desde mi computadora Linux es un gran partidario de software libre. Lo mismo vale para la educación.
deadalnix

8

El rendimiento es una característica

El artículo de Jeff Atwood es excelente para construir un sitio web de alto rendimiento y la importancia de hacerlo ...

Dicho esto, no se concentre en la microoptimización hasta que lo necesite. Hay una optimización más rentable que puede realizar. Concéntrese en la arquitectura, no en el código. La mayoría de los sitios web que he visto que han funcionado lentamente tuvieron problemas de alto nivel (capa de servicio web innecesaria, diseño de base de datos deficiente, arquitecturas demasiado complicadas) que no solo afectaron negativamente el rendimiento sino que fueron profundamente arraigados y difíciles de solucionar.

Cuando crea un sitio web, es mucho más probable que el código del lado del cliente y la lógica de la base de datos causen problemas de rendimiento que el código del lado del servidor. Sin embargo, si tiene problemas de rendimiento, lo sabrá, perfile aún mejor su código y podrá encontrarlos desde el principio.


7

El tiempo de desarrollador cuesta más que el tiempo de computadora. Eso suele ser lo que desea optimizar. Pero:

  • Hay una diferencia entre la microoptimización y la complejidad algorítmica. Dedique suficiente tiempo para estar seguro de que está utilizando el algoritmo correcto .
  • Asegúrese de hacer la pregunta correcta, select (select count(*) from foo) >= 1no es lo mismo que select exists(select 1 from foo).
  • algunos modismos lingüísticos son populares simplemente porque son más rápidos, está bien usarlos, ya que la mayoría de los usuarios con fluidez del idioma estarán familiarizados con ellos. (su ejemplo es un buen ejemplo).

7

¿Qué quieres optimizar?

  • Rendimiento del software?
  • ¿Fiabilidad?
  • Programador de productividad?
  • ¿La satisfacción del cliente?
  • ¿Eficiencia energetica?
  • Mantenibilidad?
  • ¿Hora de comprar?
  • ¿Costo?

"Optimizar" no siempre significa hacer que el código se ejecute lo más rápido posible. Hay momentos en los que es importante encontrar la forma más rápida de hacer algo, pero eso no es tan común en la mayoría de los códigos. Si los usuarios no pueden notar la diferencia entre 50 y 100 microsegundos, efectivamente no hay diferencia entre los dos en el código que solo se ejecutará ocasionalmente. Aquí hay un ejemplo:

Si necesita actualizar continuamente una visualización de la longitud de la entrada del usuario y la cantidad de tiempo que toma cualquiera de las dos rutinas para determinar que la longitud es mucho menor que el tiempo entre dos pulsaciones de tecla consecutivas, realmente no importa qué rutina tu usas. Por otro lado, si necesita determinar la longitud de mil millones de cadenas, probablemente deba prestar mucha atención a las diferencias de rendimiento entre las diferentes rutinas. En el primer caso, es posible que prefiera escribir código que sea fácil de entender y verificar; En el segundo caso, puede estar dispuesto a cambiar la legibilidad por la velocidad.

En cualquier caso, si va a optimizar su código, debe perfilarlo antes y después de cualquier cambio que realice. Los programas en estos días son tan complicados que a menudo es difícil saber dónde están los cuellos de botella; la creación de perfiles lo ayuda a optimizar el código correcto y luego muestra que las optimizaciones que realizó realmente funcionaron.

No dijiste cuándo se retiró tu padre o qué tipo de programación hizo, pero su reacción no es sorprendente. Históricamente, la memoria, el almacenamiento secundario y el tiempo de computación eran caros y, a veces, muy caros. En estos días, todas esas cosas se han vuelto muy baratas en comparación con el tiempo del programador. Al mismo tiempo, los procesadores y compiladores han podido optimizar el código de una manera que los programadores nunca podrían igualar. Los días en que los programadores usan pequeños trucos para quemar algunas instrucciones de máquina aquí y allá se han ido.


1
+1 Sin mencionar que en los últimos años, los dispositivos móviles han vuelto a depender mucho de la optimización del código. Alguien que no escribe código optimizado o al menos considera que podría tener dificultades para que su aplicación intensiva de CPU funcione sin problemas en un dispositivo móvil.
Styler

+1 se parece mucho a tu lista de posibles optimizaciones. Usó asamblea / fortran
Boz

@Styler: no pasaría mucho tiempo hasta que los dispositivos móviles tengan una CPU de cuatro núcleos con GB de memoria, ya tenemos teléfonos inteligentes de doble núcleo.
Lie Ryan

@Lie Ryan: sí, esto es cierto, pero como la mayoría de los pioneros tuvieron que viajar en botes de madera;)
Styler

7

No es importante realizar una micro optimización mientras se escribe el código. La optimización debe hacerse con la ayuda de un generador de perfiles, optimizando el código donde importa.

SIN EMBARGO , un programador debe tratar de evitar hacer cosas obviamente estúpidas mientras escribe el código.

Por ejemplo, no realice operaciones costosas repetidas dentro de un bucle. Almacene el valor en una variable fuera del ciclo y úselo. No haga cosas como comparaciones de cadenas o expresiones regulares una y otra vez en una función a menudo llamada, cuando puede subir un nivel, haga la comparación y conviértala en un entero o una referencia de función o una clase derivada.

Estas cosas son fáciles de recordar para un programador experimentado y casi siempre mejoran la calidad del código.


Me di cuenta de que necesito ser más claro en la edición de mi pregunta, estaba diciendo lo mismo realmente: lo he actualizado.
Boz

7

Al decidir qué optimizar, recuerde siempre la ley de Amdahl . Vea el enlace para matemática precisa; La declaración concisa para recordar es:

Si una parte de su programa representa el 10% de su tiempo de ejecución, y optimiza esa parte para que se ejecute el doble de rápido, el programa en su conjunto solo se acelerará en un 5%.

Esta es la razón por la cual la gente siempre dice que no vale la pena optimizar partes de su programa que no ocupan más que un pequeño porcentaje del tiempo de ejecución total. Pero ese es solo un caso especial de un principio más general. La ley de Amdahl le dice que si necesita hacer que todo el programa se ejecute el doble de rápido, debe acelerar cada pieza en un promedio del 50%. Le dice que si necesita procesar veinte gigabytes de datos, solo hay dos formas de hacerlo más rápido que el tiempo que lleva leer veinte gigabytes del disco: obtener un disco más rápido o reducir los datos.

Entonces, ¿qué dice la ley de Amdahl sobre las micro optimizaciones? Dice que tal vez valen la pena si se aplican en todos los ámbitos. Si puede reducir el uno por ciento del tiempo de ejecución de cada función en su programa, ¡felicidades! Has acelerado el programa en un uno por ciento. ¿Valió la pena hacerlo? Bueno, como compilador, estaría encantado de encontrar una optimización que hiciera eso, pero si lo haces a mano, diría que buscas algo más grande.


1
+1 para la cotización de Amdahl, pero no estoy de acuerdo con "para hacer que todo el programa se ejecute el doble de rápido, debe acelerar cada pieza". Yo diría que en realidad no aceleras ninguna "pieza". Más bien, encuentras trabajo innecesario y lo eliminas. Especialmente llamadas a funciones, si el programa es algo más grande que un juguete. Gran parte del pensamiento común sobre el rendimiento parece ignorar por completo la importancia de encontrar ramas enteras innecesarias del árbol de llamadas (que pueden ser instrucciones simples) y eliminarlas.
Mike Dunlavey

El diablo está en la palabra "promedio" allí. Es matemáticamente el caso que para acelerar un programa en un 50% cada pieza debe acelerarse en un 50% en promedio . Ahora, si puede dividir el programa en un trabajo que toma el 75% del tiempo de ejecución y otro que toma el 25%, y acelerar el primero hasta 3 veces, eso le dará un 50% en general a pesar de no haber hecho nada al último trabajo. Pero el caso mucho más común es que hay docenas de "trabajos" que requieren menos del 5% del tiempo de ejecución, y luego tienes que acelerar o deshacerte de muchos de ellos.
zwol

Creo que hay un caso aún más común. Hay un "trabajo" que toma el 50% del tiempo, pero en realidad no lo necesita , por lo que lo elimina por completo, reduciendo el tiempo total en esa cantidad y luego repite. Sé que esto es difícil de aceptar: que los programas pueden pasar grandes fracciones de tiempo haciendo cosas que (en retrospectiva) son totalmente innecesarias. Pero aquí está mi ejemplo canónico .
Mike Dunlavey

6

Depende de la etapa de desarrollo en la que se encuentre, cuando inicialmente comienza a escribir algo, las micro optimizaciones no deberían considerarse, ya que obtendrá más ganancias de rendimiento al usar buenos algoritmos que al usar micro optimizaciones. Además, considere lo que está desarrollando, ya que las aplicaciones sensibles al tiempo verán más beneficios de las consideraciones de micro optimización que las aplicaciones comerciales genéricas.

Si está probando y extendiendo software, entonces las micro optimizaciones probablemente lo perjudiquen, tienden a hacer que el código sea más difícil de leer e incluso introducen su propio conjunto único de errores que deben corregirse junto con cualquier otra cosa que deba corregirse.

Si realmente está recibiendo quejas de los usuarios sobre el código lento, entonces valdría la pena considerarlas, pero solo si todo lo demás se ha resuelto, a saber:

  • ¿Está bien escrito el código?
  • ¿La aplicación puede acceder a sus datos sin ningún problema?
  • ¿Se puede usar un mejor algoritmo?

Si todas esas preguntas han sido respondidas y todavía tiene problemas de rendimiento, entonces podría ser el momento de comenzar a usar micro optimizaciones en el código, pero es probable que otros cambios (es decir, un mejor código, un mejor algoritmo, etc.) le va a generar más de una ganancia de rendimiento que una microoptimización.


5

La velocidad de ejecución es uno de los muchos factores que contribuyen a la calidad de un programa. Muchas veces, la velocidad tiene una correlación inversa con la legibilidad / mantenibilidad. En casi todos los casos, el código debe ser legible para que se pueda mantener el código. El único momento en que la legibilidad puede verse comprometida es cuando la velocidad es un requisito esencial. El requisito de hacer que el código sea más rápido de lo que permite la legibilidad / mantenibilidad total casi nunca es aplicable, pero hay ciertos casos en los que lo hará. Lo principal a recordar es que el código micro optimizado a menudo es código hacky, por lo que, a menos que haya un requisito definido en alguna parte, casi siempre es la forma incorrecta de resolver el problema. Por ejemplo, el usuario casi nunca notará la diferencia entre tiempos de ejecución de .5 segundos y 1 segundo en operaciones CRUD, así que no necesitas entrar en un ensamblaje-interop-hackfest para llegar a esos .5 segundos. Sí, podría volar un helicóptero para trabajar y sería 10 veces más rápido, pero no lo hago debido al precio y al hecho de que el helicóptero es mucho más difícil de volar.Cuando micro optimiza el código innecesariamente, esto es exactamente lo que está haciendo: agregar complejidad y costo innecesarios para alcanzar un objetivo superfluo.


5

La microoptimización es importante cuando golpeas una restricción. Lo que le interesa puede ser la memoria, el rendimiento, la latencia o el consumo de energía. Tenga en cuenta que estas son características de nivel de sistema; no necesita (y no puede) optimizar cada función de todas las formas.

Es más probable que los sistemas integrados necesiten micro-optimización porque las restricciones se ven afectadas más fácilmente. Sin embargo, incluso allí la microoptimización solo te lleva hasta cierto punto; no puede micro-optimizar su salida de un mal diseño. El punto sobre el buen diseño en un sistema es que puede razonar sobre el sistema en su conjunto. Los componentes que necesitan micro-optimización deben estar claramente expuestos y optimizados de manera que no comprometan el diseño del sistema.

Tenga en cuenta que los pequeños sistemas "integrados" de hoy en día pueden estar bastante cerca de los Vaxen o PDP-11 de antaño, por lo que estos problemas solían ser más comunes. En un sistema moderno de propósito general que hace computación comercial general moderna, la microoptimización es rara. Probablemente esto sea parte de por qué tu padre toma la posición que él toma.

Sin embargo, no importa si se trata de nanosegundos, milisegundos, segundos u horas; Los problemas son los mismos. Deben evaluarse en el contexto del sistema y lo que está tratando de lograr.

Este es un ejemplo de una pregunta reciente que respondí en Stack Overflow para un caso en el que era necesaria una micro optimización: codificadores de video de código abierto para un sistema embebido .


4

El mayor problema con la microoptimización es que te lleva a escribir un código más difícil de mantener.

Otro problema depende de la configuración de la computadora, a veces su microoptimización podría tener un peor rendimiento que sin la 'optimización'.

Hacer muchas micro-optimizaciones consumirá mucho tiempo luchando contra algo que realmente no importa.

Un mejor enfoque es hacer un código más limpio, más fácil de mantener, y si tiene problemas de rendimiento, ejecuta un perfil para descubrir qué es lo que realmente hace que su código sea lento. Y sabiendo exactamente lo que es realmente malo, puede solucionarlo.

No estoy diciendo que no hacer micro optimizaciones es una excusa para escribir código estúpido.


4

Si comienza a preocuparse por los milisegundos, debería considerar abandonar PHP y usar C o Assembly en su lugar. No es que quisiera hacer esto, simplemente no tiene sentido discutir tales números y usar un lenguaje de secuencias de comandos. ¿Su código itera con este comando que a menudo de todos modos?

Los factores ambientales están fuera de discusión aquí, esos servidores funcionan 24/7 de todos modos y si realmente procesan algo, solo importaría si realmente es una tarea que se ejecuta durante mucho tiempo.

Lo más probable es que la luz en su oficina y la energía que nuestras computadoras usaban mientras todos escribíamos preguntas y respuestas, consumían mucha más energía que cualquier tipo de micro optimización que pueda aplicar razonablemente a sus aplicaciones.


+1 apaga la luz o no responde preguntas.
Boz

4

Debe elegir el mejor algoritmo simple para la tarea. La razón por la que debe ser simple es mantener el código legible. La razón por la que debe ser la mejor es evitar comenzar con malas características de tiempo de ejecución. No elija ciegamente BubbleSort cuando sepa que tendrá grandes conjuntos de datos. Sin embargo, está bien para el tipo ocasional de 10 elementos.

ENTONCES, si los números de perfil muestran que su elección del mejor algoritmo simple no fue lo suficientemente bueno, puede comenzar la optimización (que generalmente es el costo de la legibilidad).


BubbleSort en realidad puede ser mejor que quicksort o mergesort cuando sus datos están casi ordenados con solo unos pocos elementos extraviados que no están muy lejos de su destino final. Sin embargo, para todas las demás tareas, debe usar la función de clasificación incorporada que su lenguaje de programación le proporciona; es la forma más sencilla de comenzar (y la función de clasificación integrada en la mayoría de los idiomas tiene un buen rendimiento). MAL CONSEJO: start out with bad runtime characteristicno comience deliberadamente con una característica de mal tiempo de ejecución.
Lie Ryan

@Lie, si SABES que tus datos están casi ordenados y POR LO TANTO puedes usar bubbleort, no estás eligiendo a ciegas exactamente tu algoritmo ... También gracias por señalar el error tipográfico.

4

Lo dije antes, y lo diré aquí: "La optimización prematura es la raíz de todo mal" . Esta debería ser una de las reglas en el centro de la mente de cualquier programador.

El código puede, hasta cierto punto, siempre ser más rápido de lo que es actualmente. A menos que esté empaquetando a mano el ensamblaje con un chip en particular en mente, siempre hay algo que ganar con la optimización. Sin embargo, a menos que QUIERAS empacar a mano todo lo que haces, tiene que haber un objetivo cuantitativo, que una vez que lo cumples, dices "eso es suficiente" y dejas de optimizar, incluso si todavía hay una mirada deslumbrante por el rendimiento. usted en la cara

El código hermoso, elegante y extremadamente eficaz es inútil si no funciona (y por "trabajo" me refiero a producir la salida esperada dadas todas las entradas esperadas). Por lo tanto, producir código que funcione SIEMPRE debe ser la primera prioridad. Después de que funciona, evalúa el rendimiento y, si falta, busca formas de mejorarlo, hasta el punto en que sea lo suficientemente bueno.

Hay algunas cosas que debe decidir por adelantado que afectarán el rendimiento; decisiones muy básicas, como qué idioma / tiempo de ejecución utilizará para implementar esta solución. Muchos de estos afectarán el rendimiento en muchos órdenes de magnitud más que llamar un método frente a otro. Honestamente, PHP, como lenguaje con secuencias de comandos, ya es un éxito en el rendimiento, pero como muy pocos sitios con secuencias de comandos se crean de abajo hacia arriba en C / C ++, es comparable a otras tecnologías que probablemente elegiría (Java Servlets, ASP.NET , etc.)

Después de eso, el tamaño del mensaje de E / S es su próximo mayor factor de rendimiento. La optimización de lo que lee y escribe en el disco duro, los puertos serie, las tuberías de red, etc. generalmente mejorará el tiempo de ejecución del programa en muchos órdenes de magnitud, incluso si los algoritmos detrás de las operaciones de E / S fueran eficientes. Después de eso, reduzca la complejidad Big-O del algoritmo en sí, y luego, si es absolutamente necesario, puede "micro-optimizar" eligiendo llamadas a métodos menos costosos y tomando otras decisiones esotéricas a niveles bajos.


2
+1 Producir código que funcione SIEMPRE debe ser la primera prioridad.
Boz

2
@Keith, en realidad Knuth lo dijo primero, y dijo un poco más que eso.

"Haz que funcione, luego haz que funcione tan rápido como sea necesario", Anon.
John Saunders

1
En realidad, la religión es la raíz de todo mal, pero estoy divagando.
Thomas Eding

4

Mencionas que tu papá es un programador retirado. Los programadores que trabajaban en el mundo de mainframe tenían que estar muy preocupados por el rendimiento. Recuerdo haber estudiado una actividad de la Marina de los EE. UU. En la que su computadora central estaba limitada por hardware a 64 KB de memoria por usuario. En ese mundo de programación tienes que buscar cada poquito que puedas.

Las cosas son muy diferentes ahora y la mayoría de los programadores no necesitan preocuparse tanto por las micro optimizaciones. Sin embargo, los programadores de sistemas embebidos todavía lo hacen y las personas de bases de datos todavía necesitan usar código optimizado.


3

El código debe estar escrito para ser absolutamente claro sobre lo que hace. Entonces, si y solo si es demasiado lento, retrocede y acelera. El código siempre se puede cambiar para que sea más rápido más tarde, si se puede entender, pero buena suerte cambiándolo para que quede claro si es rápido.


3

Es importante si:

1) La vida de alguien depende de tu código. Una función que tarda 25 ms en ejecutarse en el monitor de frecuencia cardíaca de alguien es probablemente una mala idea.

Personalmente, adopto un enfoque doble: hay micro optimizaciones que puede hacer que no afectarán la legibilidad, obviamente desea usarlas. Pero si afecta la legibilidad, espere: no obtendrá muchos beneficios y, en realidad, podría llevarle más tiempo depurar a largo plazo.


2
Solo algunos puntos menores en su ejemplo: una función en un monitor de frecuencia cardíaca que tome 25 ms no sería un problema, siempre y cuando otras tareas necesarias pudieran ocurrir con el tiempo de respuesta requerido. Las interrupciones son buenas para esto. Y la latencia de 25 ms para algo que solo está monitoreando eventos del mundo real para actualizar una pantalla para consumo humano probablemente no sea un problema.
enero

3

¿Es importante la microoptimización al codificar?

No, dado que hay plataformas como JVM y .NET donde el código está escrito para una máquina virtual y, por lo tanto, tratar de optimizar la ejecución puede no funcionar tan bien como lo que es óptimo en el escritorio de un desarrollador no es necesariamente lo mismo en un servidor. Mire qué tan lejos del hardware están algunas de estas piezas de software de alto nivel para otro punto aquí. Algo a considerar es la diversidad de hardware, ¿qué tan realista es optimizar el código para chips específicos como una CPU o GPU cuando un nuevo modelo probablemente saldrá en menos de un año?

Otra cuestión a considerar aquí es el rendimiento medido por qué métrica: velocidad de ejecución, memoria utilizada en la ejecución, velocidad de desarrollo de nuevas características, tamaño de la base de código en un servidor en formas compiladas o descompiladas, escalabilidad, mantenibilidad, etc. .? Si se toma de manera lo suficientemente amplia, la pregunta se vuelve trivial, pero no estoy seguro de cuán ampliamente quisiste tomar el rendimiento, ya que realmente puede ser casi cualquier cosa, siempre que pueda medirse de alguna manera.


Algunas micro optimizaciones pueden funcionar y otras pueden no funcionar, que es donde uno puede preguntarse cuánto vale la pena realizar dicho trabajo en comparación con otro trabajo que puede considerarse como una prioridad mucho más alta, como nuevas características o corregir errores. La otra pregunta sería si una actualización de hardware o software también puede romper algunas de esas optimizaciones.


1
Tenga en cuenta que absolutamente puede hacer microoptimizaciones en plataformas como JVM y .NET, simplemente toman formas ligeramente diferentes. Pero lo mismo es cierto si compara un compilador C simple y antiguo con un compilador más moderno y altamente optimizador: las optimizaciones que el usuario puede hacer se verán diferentes.
Joachim Sauer

1

Creo que hay una gran diferencia entre una buena programación y una microoptimización.

Si hay dos formas de hacer la misma tarea, una es más rápida que la otra y ambas tienen la misma legibilidad, debe usar la más rápida. Siempre. Y esta es una buena programación. No hay razón para no usar un mejor algoritmo para resolver un problema. E incluso documentarlo es fácil: proporcione el nombre del algoritmo, todos podrán buscarlo en Google y encontrar más información sobre cómo funciona.

Y buenos algoritmos ya están optimizados. Serán rápidos Serán pequeños Usarán la memoria mínima requerida.

Incluso si los usa su programa todavía no tiene ese rendimiento, puede considerar microoptimizarlo. Y tendrá que conocer realmente el idioma para poder realizar una micro optimización.

Y siempre hay espacio para gastar más dinero en hardware. El hardware es barato, los programadores son caros . No gaste demasiado tiempo / dinero optimizando cuándo puede comprar hardware.


1

La legibilidad del código en mi humilde opinión es más importante que la microoptimización porque en la mayoría de los casos la microoptimización no vale la pena.

Artículo sobre micro optimizaciones sin sentido :

Como la mayoría de nosotros, estoy cansado de leer publicaciones de blog sobre micro optimizaciones sin sentido, como reemplazar print por echo, ++ $ i por $ i ++, o comillas dobles por comillas simples. ¿Por qué? Porque 99.999999% del tiempo, es irrelevante. ¿Por qué? Debido a que el 99.99% del tiempo, será mejor que instale un acelerador PHP como APC, o agregue estos índices faltantes en las columnas de su base de datos, o intente evitar esas 1000 solicitudes de base de datos que tiene en la página de inicio.

print usa un código de operación más porque en realidad devuelve algo. Podemos concluir que el eco es más rápido que la impresión. Pero un código de operación no cuesta nada, realmente nada.

He intentado en una nueva instalación de WordPress. El script se detiene antes de terminar con un "Error de bus" en mi computadora portátil, pero el número de códigos de operación ya era de más de 2.3 millones. Basta de charla.

Entonces, en la mayoría de los casos, la microoptimización ahorra 1 operación entre millones, pero empeora la legibilidad.


1

Otras respuestas son correctas sobre el dinero. Pero agregaré otro punto en el que uno tiene que diferenciar qué es la optimización / microoptimización prematura y escribir código performante que refleje una comprensión del comportamiento de las construcciones del lenguaje / marco (lo siento, no pude encontrar una palabra para el último) . ¡La última es una buena práctica de codificación y generalmente se debe hacer!

Lo explicaré. La mala optimización (lectura de optimización prematura / micro) no es cuando optimiza secciones de código sin crear perfiles para saber si realmente son los cuellos de botella. Es cuando optimiza en función de sus suposiciones, rumores y comportamientos indocumentados. Si está documentado y hace algo de una manera más eficiente / lógica por pequeña que sea, lo llamo buena optimización . Como han dicho otros, ambos tienen inconvenientes y casi no tienen nada de profesionales en lo que respecta a ganar un buen negocio, pero aún así hago lo último, no lo primero, si no vence totalmente la legibilidad. Sí, la legibilidad / mantenibilidad es de suma importancia y se trata de dónde trazar la línea.

Reitero los puntos hechos por otros aquí como la inutilidad de las optimizaciones buenas y malas:

  1. Sus dependencias a un problema específico pueden cambiar y cualquier tiempo dedicado a la optimización antes de completar la sección lógica de su aplicación es una pérdida de tiempo. Me refiero a la optimización en una etapa relativamente temprana. Hoy tiene una List<T>y para cuando se envía su aplicación, tenía que cambiarla LinkedList<T>y ahora toda la evaluación comparativa era una pérdida de tiempo y esfuerzo.

  2. En su mayoría, el verdadero cuello de botella de su aplicación (leída como una diferencia medible) podría ser el 5% de su código (principalmente los sql) y la optimización del otro 95% no brinda a sus clientes ningún beneficio.

  3. Por lo general, el código "técnicamente" de mejor rendimiento significa más verbosidad, lo que a su vez significa más código propenso a errores, lo que a su vez significa una mayor capacidad de mantenimiento y más tiempo invertido, lo que a su vez significa que gana menos dinero.

  4. La huella de carbono que ahorra para todo el mundo a través de una ganancia de rendimiento del 1% se ve fácilmente eclipsada por los gases de efecto invernadero que su equipo tendrá que emitir al depurar y mantener ese código.

Los aspectos negativos de la mala optimización en particular son:

  1. A menudo no te da el rendimiento que esperas. Vea esta pregunta en SO, donde las optimizaciones han fallado . De hecho, puede tener efectos adversos. Ese es el problema con el comportamiento indocumentado.

  2. La mayoría de los compiladores modernos lo harán por usted de todos modos.

Daré algunos ejemplos de optimización buena y mala:

El malo -

  1. uso de tipos enteros más pequeños en lugar de Int32.

  2. ++i usado en lugar de i++

  3. foren lugar de foreach(lo peor que he visto, derrota totalmente la lógica)

  4. evitando variables cerradas

    string p;
    foreach (var item in collection)
        p = ...;
    
  5. usando en charlugar de cadena durante la concatenación de cadenas, como:

    string me = 'i' + "me myself"; // something along that line - causes boxing
    

Lo bueno (del mundo .NET. Debe explicarse por sí mismo) -

  1. Doble búsqueda

    if (Dictionary<K, V>.TryGetValue(K, out V))
        do something with V
    

    en lugar de

    if (Dictionary<K, V>.ContainsKey(K))
        do something with Dictionary<K, V>[K]
    
  2. Cargalos todos

    DirectoryInfo.EnumerateFiles();
    

    en lugar de

    DirectoryInfo.GetFiles();
    
  3. Casting en dos etapas:

    s = o as string;
    if (s != null)
        proceed
    

    en lugar de

    if (o is string)
        s = (string)o;
    
  4. Si el orden no importa

    if (counter < X || expensiveFunction())
    

    en lugar de

    if (expensiveFunction() || counter < X)
    
  5. Boxeo

    void M<T>(T o) //avoids boxing
    {
    
    }
    

    en lugar de

    void M(object o)
    {
    
    }
    

Si me pregunta si esto proporciona beneficios de rendimiento notables, le diría que no. Pero sugeriría que uno debería usarlos porque se deriva de una comprensión del comportamiento de estas construcciones. ¿Por qué hacer dos llamadas cuando solo puedes hacer 1? Desde un punto de vista filosófico, es una buena práctica de codificación. Y 1 y 3 también son un poco menos legibles en términos estrictos, pero ¿prevalecen sobre la legibilidad? No, no mucho, así que lo uso. Ahora esa es la clave: mantener una relación de rendimiento a legibilidad decente. Y cuando es eso, se trata de dónde trazas la línea.


1

"Vale la pena" necesita contexto, por ejemplo, cuánto más simple es escribir, leer y mantener frente a cuánto más rápido hace que el usuario tenga algo más receptivo, interactivo y requiere menos tiempo para que espere.

Ahorrar unos centavos para comprar una lata de refresco no me hará mucho bien si tengo que viajar una distancia para ahorrar esos centavos, especialmente dado que rara vez bebo refrescos en estos días. Ahorrar unos centavos por lata en una compra de un millón de latas de refresco podría ser un gran problema.

Mientras tanto, ahorro unos centavos cuando dos personas están justo a mi lado y una ofrece exactamente lo mismo por unos centavos más baratos y la otra no, y elijo la más cara porque me gusta más su sombrero parece un caso tonto de pesimismo.

Lo que a menudo encuentro que las personas que llaman "microoptimizaciones" parecen estar curiosamente desprovistas de mediciones, contexto y discusión sobre el usuario final, cuando debería haber absolutamente los tres para considerar tales optimizaciones si no son triviales de aplicar. Para mí, una microoptimización adecuada en estos días se relaciona con cosas como diseños de memoria y patrones de acceso, y aunque pueden parecer "micro" en foco, no son micro en efecto.

Logré, no hace mucho tiempo, reducir una operación de 24 segundos a 25 milisegundos (aproximadamente 960 veces más rápido), con salidas idénticas (aseguradas por pruebas automatizadas), sin cambios en la complejidad algorítmica, para el revestimiento de difusión de calor volumétrico, a través de "micro-optimizaciones" (la mayor de las cuales provino de un cambio en el diseño de la memoria que lo redujo a unos 2 segundos, luego el resto fueron cosas como SIMD y análisis adicionales de errores de caché en VTune y algunos cambios en el diseño de la memoria).

Wolfire explica la técnica aquí, y luchó con el tiempo requerido: http://blog.wolfire.com/2009/11/volumetric-heat-diffusion-skinning/

Mi implementación logró hacerlo en milisegundos mientras luchaba por reducirlo a menos de un minuto: ingrese la descripción de la imagen aquí

Después de "microoptimizarlo" de 24 segundos a 25 ms, eso cambió el juego en el flujo de trabajo. Ahora los artistas pueden cambiar sus plataformas en tiempo real a más de 30 FPS sin esperar 24 segundos cada vez que realicen algún pequeño cambio en su plataforma. Y eso realmente cambió todo el diseño de mi software ya que ya no necesitaba la barra de progreso y cosas de este tipo, todo se volvió interactivo. De modo que podría ser una "microoptimización" en el sentido de que todas las mejoras se produjeron sin ninguna mejora en la complejidad algorítmica, pero en efecto fue una "megaoptimización" que hizo lo que antes era un proceso doloroso y no interactivo. en uno interactivo en tiempo real que cambió por completo la forma en que trabajaban los usuarios.

Medición, requisitos del usuario final, contexto

Realmente me gustó el comentario de Robert aquí y tal vez no logré hacer el punto que quería:

Bueno, vamos. Nadie va a argumentar que este tipo de cambio no "vale la pena". Pudiste demostrar un beneficio tangible; muchas de las llamadas micro optimizaciones no pueden.

Esta es, a pesar de trabajar en un campo muy crítico para el rendimiento con requisitos a menudo en tiempo real, la única vez que considero cualquier micro-optimización que requiera salir de mi camino.

Y enfatizaría no solo las mediciones sino también el lado del usuario final. Soy un bicho raro porque llegué a mi campo actual (y anteriormente gamedev) como usuario / fan primero, desarrollador segundo. Así que nunca me entusiasmaron tanto las cosas habituales que entusiasman a los programadores como resolver acertijos técnicos; Los encontré una carga, pero los soportaría a través del sueño del usuario final que compartí con otros usuarios. Pero eso me ayudó a asegurarme de que si estaba optimizando algo, tendría un impacto real en los usuarios con beneficios reales. Es mi salvaguarda contra la micro-optimización sin rumbo.

En mi opinión, eso es realmente tan importante como el perfilador, porque tenía colegas que hicieron cosas como la subdivisión de micro-optimización de un cubo en mil millones de facetas solo para ahogarse en modelos de producción del mundo real como personajes y vehículos. Su resultado fue impresionante en cierto sentido de "demostración tecnológica", pero casi inútil para los usuarios reales, porque estaban perfilando y midiendo y comparando casos que no se alineaban con los casos de uso del mundo real. Por lo tanto, es muy importante comprender primero lo que es importante para los usuarios, ya sea aprendiendo a pensar y usar el software como tal o colaborando con ellos (idealmente ambos, pero al menos colaborar con ellos).


2
Bueno, vamos. Nadie va a argumentar que este tipo de cambio no "vale la pena". Pudiste demostrar un beneficio tangible; muchas de las llamadas micro optimizaciones no pueden.
Robert Harvey

1
@RobertHarvey Era el punto que esperaba hacer, ya que lo que algunas personas llaman "microoptimización" no es necesariamente microscópico en efecto, pero depende mucho del contexto, las mediciones, etc. issetvs. strlenparece más minúsculo en foco ausente el contexto y las medidas. :-D
Dragon Energy

1
@RobertHarvey Tenía la esperanza de decir, aunque sea indirectamente, que si hay un contexto negativo para las "micro optimizaciones", es el tipo que tiende a carecer de esas medidas, contextos y necesidades del usuario final. También podría continuar con el último caso, ya que tenía un colega que optimizó muchísimo algo que era genial, excepto que nadie lo usó. Incluso creo que la optimización adecuada requiere cierta comprensión del usuario final, de lo contrario podríamos estar perfilando y ajustando cosas que a los usuarios no les interesan.
Dragon Energy

1
Algunas optimizaciones son impulsadas por la necesidad apremiante, mientras que otras son impulsadas por la curiosidad (búsqueda intelectual y aventurerismo). Necesitamos los dos. En la historia de Dragon Energy, probablemente no era una "necesidad apremiante", ya que los artistas aparentemente no se quejaron en voz alta por no ver ningún resultado de renderizado hasta 24 segundos después de cada edición. De hecho, los usuarios pueden no saber qué tan rápido pudo haber sido, hasta que un programador invirtió en todo el esfuerzo para batir el récord de velocidad. Limitarnos a la demanda impulsada tiene sentido comercial, pero al hacerlo perderá algunas oportunidades de optimización sorprendentes o cambios en el juego.
rwong

1
Hablando de sentido comercial, también está el problema de la monetización. Cada movimiento (por ejemplo, un programador que trabaja en la optimización del rendimiento) cuesta dinero, y el costo debe recuperarse para que el negocio tenga sentido. Por lo tanto, uno tiene que preguntarse si la mejora de velocidad que cambia el juego se puede "vender", o cuánto dinero se "ahorraría", si el programador debe obtener la aprobación de un gerente comercial.
rwong

0

Lo diré de esta manera: la microoptimización es un proceso de optimización de algo que no es un cuello de botella. Por ejemplo, si su programa llama a dos funciones A y B, y A tarda 100 milisegundos en completarse y B tarda 2 microsegundos, y sigue optimizando la función B. Eso no solo no es importante, es absolutamente incorrecto. Pero la función de optimización B se llama optimización y no microoptimización. Importancia de la optimización depende. Digamos que no tiene nada más que hacer y su programa está libre de errores, entonces sí, es importante. Pero generalmente tienes prioridades. Digamos que necesita agregar / escribir la función C. Si cree que escribir la función C le dará más dinero que hacer que su programa sea más rápido sin esa funcionalidad, entonces vaya a la optimización. De lo contrario, busque la funcionalidad. También, Los programadores experimentados centrados en el rendimiento no pasan mucho tiempo optimizando, simplemente escriben programas rápidos. Por lo menos saben qué herramientas usar y qué hacer para no pasar años haciendo optimizaciones sin sentido (leer micro).


esta publicación es bastante difícil de leer (muro de texto). ¿Te importaría editarlo en una mejor forma?
mosquito
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.