"La optimización prematura es la raíz de todo mal" es algo que casi todos hemos escuchado / leído. Lo que tengo curiosidad es qué tipo de optimización no es prematura, es decir, en cada etapa del desarrollo de software (diseño de alto nivel, diseño detallado, implementación de alto nivel, implementación detallada, etc.), ¿qué grado de optimización podemos considerar sin que se cruce al lado oscuro?
optimization
Gaurav
fuente
fuente
Respuestas:
¿Cuándo lo estás basando en la experiencia? No es malvado "Cada vez que hacemos X, sufrimos un golpe brutal en el rendimiento. Planifiquemos optimizar o evitar X por completo esta vez".
Cuando es relativamente indoloro? No es malvado "Implementar esto como Foo o Bar requerirá tanto trabajo, pero en teoría, Bar debería ser mucho más eficiente. Barremos".
¿Cuándo evitas algoritmos de mierda que se escalarán terriblemente? No es malvado "Nuestro líder técnico dice que nuestro algoritmo de selección de ruta propuesto se ejecuta en tiempo factorial; no estoy seguro de lo que eso significa, pero ella sugiere que cometamos seppuku incluso por considerarlo. Consideremos otra cosa".
El mal proviene de pasar mucho tiempo y energía para resolver problemas que no sabes que realmente existen. Cuando los problemas definitivamente existen, o cuando los psudoproblemas fantasmas pueden resolverse a bajo precio, el mal desaparece.
Steve314 y Matthieu M. plantean puntos en los comentarios que deberían considerarse. Básicamente, algunas variedades de optimizaciones "indoloras" simplemente no valen la pena, ya que la mejora de rendimiento trivial que ofrecen no vale la ofuscación del código, están duplicando las mejoras que el compilador ya está realizando, o ambas cosas. Vea los comentarios para ver algunos ejemplos agradables de no mejoras demasiado inteligentes a la mitad.
fuente
i
no está firmado,i / 2
se puede reemplazar pori >> 1
. Es mas rapido. Pero también es más críptico (no todos verán el efecto, incluso aquellos que lo hagan pueden perder tiempo). Pero lo peor de todo es que el compilador lo hará de todos modos, entonces, ¿por qué ofuscar el código fuente;)?i/2
es realmente un punto caliente y eso (increíble, pero supongamos) loi>>1
hace más rápido, hágalo, y póngale un comentario que este perfil mostró que es más rápido. Si esto es realmente necesario en cualquier lugar (lo cual dudo, ya que, como dijo Matthieu, los compiladores deberían ser lo suficientemente inteligentes como para hacerlo ellos mismos), los novatos aprenderán algo, si no lo es (lo que es probable), ¿por qué quieres conectarlo? sus cabezas con folklore innecesario?El código de la aplicación solo debe ser tan bueno como sea necesario, pero el código de la biblioteca debe ser lo mejor posible, ya que nunca se sabe cómo se va a utilizar su biblioteca. Entonces, cuando escribe código de biblioteca, debe ser bueno en todos los aspectos, ya sea rendimiento, solidez o cualquier otra categoría.
Además, debe pensar en el rendimiento al diseñar su aplicación y al elegir algoritmos . Si no está diseñado para ser eficaz, ningún grado de piratería informática puede ser eficaz después y ninguna micro-optimización superará a un algoritmo superior.
fuente
Del tipo que viene como resultado de problemas conocidos.
fuente
Es difícil decir qué es bueno y malo. ¿Quién tiene ese derecho? Si observamos la naturaleza, parece que estamos programados para la supervivencia con una definición amplia de "supervivencia" que incluye transmitir nuestros genes a la descendencia.
Entonces, diría, al menos de acuerdo con nuestras funciones básicas y programación, que la optimización no es mala cuando se alinea con el objetivo de la reproducción. Para los chicos, están las rubias, morenas, pelirrojas, muchas encantadoras. Para las chicas, hay chicos, y algunos de ellos parecen estar bien.
Quizás deberíamos estar optimizando para ese propósito, y allí ayuda usar un generador de perfiles. El generador de perfiles le permitirá priorizar sus optimizaciones y el tiempo de manera más efectiva además de brindarle información detallada sobre los puntos de acceso y por qué ocurren. Esto le dará más tiempo libre dedicado a la reproducción y su búsqueda.
fuente
La cita completa define cuándo la optimización no es prematura:
Puede identificar el código crítico de muchas maneras: las estructuras o algoritmos de datos críticos (por ejemplo, utilizados en gran medida o el "núcleo" del proyecto) pueden proporcionar optimizaciones importantes, muchas optimizaciones menores se identifican a través de los perfiladores, etc.
fuente
Siempre debe elegir una solución "suficientemente buena" en todos los casos según sus experiencias.
El dicho de optimización se refiere a escribir "código más complejo que 'lo suficientemente bueno' para hacerlo más rápido" antes de saber que es necesario, por lo que el código es más complejo de lo necesario. La complejidad es lo que dificulta las cosas, por lo que no es algo bueno.
Esto significa que no debe elegir una rutina de clasificación súper compleja "puede ordenar archivos de 100 Gb intercambiando de manera transparente al disco" cuando lo haga una ordenación simple, pero también debe hacer una buena elección para la ordenación simple en primer lugar. Elegir ciegamente Bubble Sort o "seleccionar todas las entradas al azar y ver si están en orden. Repita". Raramente es bueno.
fuente
Mi regla general: si no está seguro de que necesitará la optimización, suponga que no. Pero tenlo en cuenta para cuando necesites optimizar. Sin embargo, hay algunos problemas que puede conocer por adelantado. Esto generalmente implica elegir buenos algoritmos y estructuras de datos. Por ejemplo, si necesita verificar la membresía en una colección, puede estar bastante seguro de que necesitará algún tipo de estructura de datos establecida.
fuente
En mi experiencia, en la fase de implementación detallada, la respuesta está en el perfil del código. Es importante saber qué necesita ser más rápido y qué es aceptablemente rápido.
También es importante saber dónde se encuentra exactamente el cuello de botella en el rendimiento: la optimización de una parte del código que toma solo el 5% del tiempo total para ejecutarse no sirve de nada.
Los pasos 2 y 3 describen la optimización no prematura:
fuente
No es optimización al elegir cosas que son difíciles de cambiar, por ejemplo: plataforma de hardware.
Elegir estructuras de datos es un buen ejemplo, crítico para cumplir con los requisitos funcionales y no funcionales (rendimiento). No se cambia fácilmente y, sin embargo, controlará todo lo demás en su aplicación. Sus estructuras de datos cambian los algoritmos disponibles, etc.
fuente
Solo conozco una forma de responder a esta pregunta, y es obtener experiencia en el ajuste del rendimiento. Eso significa: escribir programas, y después de que se escriben, encontrar aceleraciones en ellos y hacerlo de forma iterativa. Aquí hay un ejemplo.
Este es el error que comete la mayoría de las personas: intentan optimizar el programa antes de ejecutarlo. Si han tomado un curso de programación (de un profesor que en realidad no tiene mucha experiencia práctica) tendrán anteojos grandes de color O, y pensarán que de eso se trata . Es todo el mismo problema, optimización previa. **
Alguien dijo: Primero hazlo bien, luego hazlo rápido. Tenían razón
Pero ahora para el pateador: si has hecho esto varias veces, reconoces las cosas tontas que hiciste antes que causan problemas de velocidad, por lo que las evitas instintivamente. (Cosas como hacer que la estructura de tu clase sea demasiado pesada, inundarte de notificaciones, confundir el tamaño de las llamadas de función con su costo de tiempo, la lista sigue y sigue ...) Instintivamente las evitas, pero adivina cómo se ve al menos. experimentado: optimización prematura!
Así que estos debates tontos siguen y siguen :)
** Otra cosa que dicen es que ya no tienes que preocuparte por eso, porque los compiladores son muy buenos y las máquinas son tan rápidas hoy en día. (KIWI - Kill It With Iron.) No hay aceleraciones exponenciales del hardware o del sistema (realizadas por ingenieros muy inteligentes y trabajadores) que posiblemente puedan compensar la desaceleración exponencial del software (realizada por programadores que piensan de esta manera).
fuente
Cuando los requisitos o el mercado lo solicite específicamente.
Por ejemplo, el rendimiento es un requisito en la mayoría de las aplicaciones financieras porque la baja latencia es crucial. Dependiendo de la naturaleza del instrumento comercializado, la optimización puede ir desde el uso de algoritmos sin bloqueo en un lenguaje de alto nivel hasta el uso de un lenguaje de bajo nivel e incluso el extremo: implementar los algoritmos de coincidencia de órdenes en el hardware mismo (usando FPGA por ejemplo )
Otro ejemplo sería algunos tipos de dispositivos integrados. Tomemos por ejemplo el freno ABS; en primer lugar está la seguridad, cuando golpeas el freno, el auto debe disminuir la velocidad. Pero también hay rendimiento, no querrás demoras cuando llegues al descanso.
fuente
La mayoría de las personas llamaría a la optimización prematura, si está optimizando algo que no está dando como resultado un "fallo suave" (funciona pero sigue siendo inútil) del sistema debido al rendimiento.
Ejemplos del mundo real.
Si mi ordenamiento de burbujas tarda 20 ms en ejecutarse, optimizarlo a 1 ms de clasificación rápida no mejorará la utilidad general de ninguna manera significativa a pesar de ser un aumento del rendimiento del 2000%.
Si una página web tarda 20 segundos en cargarse y la reducimos a 1 segundo, esto puede aumentar la utilidad del sitio web de 0 a casi infinito. Básicamente, algo que se rompió porque era demasiado lento, ahora es útil.
fuente
¿Qué tipo de optimización no es prematura?
Una optimización que corrige un problema de rendimiento conocido con su aplicación, o una optimización que permite que su aplicación cumpla con criterios de aceptación bien definidos.
Una vez identificados, se debe tomar un tiempo para establecer la solución y se debe medir el beneficio de rendimiento.
(es decir, no lo es: "Creo que esta parte del código parece que podría ser lenta, cambiaré X para usar Y y eso será más rápido").
Me he encontrado con una gran cantidad de "optimización" prematura que finalmente ha hecho que el código sea más lento; en este caso, estoy tomando prematuro para significar "no pensado". El rendimiento debe ser comparado antes y después de la optimización y solo se debe mantener un código que realmente mejore el rendimiento.
fuente
Cierto. Desafortunadamente, también es una de las citas de programación más mal utilizadas (maliciosamente) de todos los tiempos. Como Donald Knuth acuñó el meme, vale la pena agregar un contexto original de la cita:
Tenga en cuenta que Knuth habló específicamente sobre la velocidad de ejecución en tiempo de ejecución .
Además, escribió el artículo en 1974 cuando cualquier recurso de máquina donde la correlación premium y negativa entre la velocidad de ejecución y la capacidad de mantenimiento del programa (mayor velocidad - menos mantenible) probablemente era más fuerte que ahora.
OK, para responder a su pregunta, según Donald Knuth, la optimización NO es prematura si soluciona un serio cuello de botella de rendimiento que se ha identificado (idealmente medido y señalado durante el perfilado).
Como dije antes, la "optimización prematura" es uno de los memes más mal utilizados, por lo que la respuesta no estará completa sin algunos ejemplos de cosas que no son optimizaciones prematuras pero que a veces se ignoran como tales:
Además, ni siquiera están relacionados con la velocidad de ejecución del tiempo de ejecución:
diseño inicial reflexivo
escritura estática (!)
etc. / cualquier forma de esfuerzo mental
fuente