Mientras construyo aplicaciones, me pregunto constantemente si esta es la mejor manera de realizar o implementar una determinada funcionalidad. A menudo, publicaré preguntas en stackoverflow u otro foro que desee comentarios solo para recibir comentarios sobre cómo no "poner el carro antes que el caballo" con respecto al rendimiento. ¿La mayoría de los programadores realmente no piensan en el rendimiento hasta que finaliza la aplicación, o el rendimiento es absolutamente inaceptable? Quiero decir, entiendo que los entornos de desarrollo difieren de los entornos de producción y que no debe confiar completamente en los resultados de su computadora portátil de desarrollo ... pero, hay prácticas y técnicas que producen un mejor rendimiento que otras.
¿Es una mala práctica considerar el rendimiento durante todo el proceso de desarrollo? ¿Debería dejar de lado estas consideraciones hasta que el rendimiento se esté hundiendo?
Actualizar
Para que quede claro, estoy hablando de la situación en la que está considerando o a punto de trabajar en alguna funcionalidad. Usted sabe que hay varias formas de implementarlo, pero no está seguro de qué tan bien se escalará cada implementación. También puede haber varias técnicas con las que ni siquiera estás familiarizado. A pequeña escala, cualquiera de los enfoques probablemente sería adecuado, pero a mayor escala, algunos seguirán el ritmo y otros no. A menudo, cuando pido opiniones u orientación, la respuesta es: preocúpese más tarde ...
fuente
Respuestas:
El aplazamiento de las consideraciones de rendimiento a veces se basa en una aplicación incorrecta de la frase:
Si lee la cita completa, lo que Knuth intentaba decir es que las microoptimizaciones aplicadas durante el desarrollo sin creación de perfiles generalmente no son recomendables, ya que conducen a un código menos mantenible sin necesariamente lograr beneficios sustanciales de rendimiento.
Pero eso no significa que no deba considerar el rendimiento hasta que la aplicación esté casi terminada. Si hace eso, puede encontrar que el rendimiento es inadecuado, su arquitectura de diseño no admite un mejor rendimiento y debe comenzar de nuevo.
Hay varias cosas que puede hacer durante el desarrollo para lograr un buen rendimiento, sin optimizaciones esotéricas (y prematuras):
Si hace estas cosas, encontrará que cualquier optimización de rendimiento que deba realizarse se limitará a una pequeña parte de su código. La creación de perfiles identificará ese código y le permitirá enfocar sus mejoras de rendimiento donde harán más bien, sin sacrificar la mantenibilidad.
fuente
Esto es lo que NO DEBE pensar:
++i
más rápido quei++
?switch
más rápido queif
?inline
mis funciones?Esto es lo que PENSAR:
Con respecto a este último punto, en mi experiencia, es mejor diseñar la estructura de datos para que, si no debe normalizarse, pueda tolerar inconsistencias temporales, que luego pueden resolverse mediante algún tipo de barrido periódico. Un asesino importante del rendimiento es cuando las notificaciones desencadenan más notificaciones, que desencadenan aún más, en una medida que nunca habrías adivinado de antemano. Y a menudo es un esfuerzo desperdiciado debido a los cambios auto cancelables.
Si has hecho todo esto, tienes un diseño limpio. Luego, periódicamente a medida que lo desarrolles, perfila. ( La pausa aleatoria es el método en el que confío). Entonces, si puede ver que el rendimiento mejoraría al incorporar un algoritmo más sofisticado, hágalo de todas maneras.
fuente
No, debe pensar en el rendimiento (especialmente en el diseño de bases de datos) desde el principio. Ha habido mucho daño a nuestra industria por parte de personas que piensan que cualquier optimización es una optimización prematura. La cita originalmente tenía la intención de evitar que las personas vieran micro optimizaciones antes de que ocurriera un problema. No pretendía no hacer ninguna optimización en absoluto. En una base de datos, por ejemplo, hay muchas técnicas conocidas que funcionan mal. Evitar eso, en el diseño, es parte de lo que debe hacer. Es muy difícil refactorizar una base de datos con 100,000,000 registros porque fue diseñada usando técnicas de bajo rendimiento y ya no podemos evitar el problema comprando un mejor hardware.
fuente
Preocúpese primero por la corrección 1 , luego la capacidad de mantenimiento, luego la seguridad y la fiabilidad, y luego puede pensar en el rendimiento. Aplique este orden a cada fragmento de código mientras lo desarrolla. Es posible que una solución eficaz se caiga naturalmente de mantener las cosas claras y directas.
El 80% del rendimiento es elegir el algoritmo y la estructura de datos correctos para el problema en cuestión; un ordenamiento rápido mal optimizado todavía está superando a un tipo de burbuja altamente optimizado en el caso promedio (el peor de los casos es un empate).
Lo que todo el mundo en SO está tratando de descifrar es la mentalidad "que es más rápido, ++ p o p ++", donde las personas quedan tan atrapadas en burlar al compilador que pierden el rastro del problema más grande, lo que resulta en un código que es frágil, error - retenido, incorrecto y lo mejor de todo, no mucho más rápido de lo que hubiera sido una solución más sencilla. He tratado con ese tipo de código de primera mano; Un ejemplo fue tan frágil que no pudimos hacer ningún cambio sin romperlo por completo.
1 Donde "corrección" significa "cumplir con la especificación", que no es sinónimo de "libre de errores".
fuente
Debería comenzar a pensar en el rendimiento una vez que sepa qué es el "buen" rendimiento. En otras palabras, sería un error comenzar a pensar en el rendimiento antes de identificar cuáles son los siguientes umbrales:
Una vez que haya identificado cuáles son esos umbrales, también ha identificado la métrica que está utilizando para medir el rendimiento. Eso significa que puede configurar algunas pruebas de rendimiento automatizadas que puede ejecutar varias veces al día. Eso le dirá si está mejorando o empeorando.
Para llegar a esas métricas, debe comprender qué debe hacer su sistema. Por ejemplo, ¿se requieren métricas de rendimiento absoluto (respuesta dentro del tiempo X) o se requieren mediciones de rendimiento (respuestas X por tiempo Y)? El rendimiento y las optimizaciones de tiempo absoluto requieren diferentes enfoques, y si no sabe lo que es realmente importante, podría estar optimizando el camino equivocado.
fuente
Probablemente hayas escuchado que la optimización prematura es la raíz de todo mal. La pregunta es ¿qué lo hace prematuro? En mi opinión, nunca es una mala idea pensar en el rendimiento, pero no se preocupe demasiado hasta que su código funcione. Una vez que funcione, realice algunas pruebas de carga pesada, perfile e identifique cuellos de botella y optimice su rendimiento.
Dicho esto, no hay nada de malo en pensar en el rendimiento durante la etapa de codificación inicial si sabe ciertas técnicas que marcarán una diferencia real. Por ejemplo, elegir una estructura de almacenamiento de una biblioteca sobre otra porque la experiencia previa le ha enseñado que una de ellas es más rápida / usa menos RAM que la otra. O construir en un sistema de almacenamiento en caché simple (puede hacerlo más sofisticado si las pruebas posteriores lo requieren) para los datos que conoce que se accederá mucho y se almacenará en caché mucho mejor. De esta manera, no te preocupas demasiado por el rendimiento (al menos no inicialmente), pero estás usando consejos y trucos que has aprendido en el camino de otros proyectos. Trate de mantener estos simples para que sean fáciles de incluir durante el desarrollo inicial y también puedan ofrecer algún beneficio.
fuente
El rendimiento debe detallarse en el sistema y las especificaciones relacionadas con el usuario de su Documento de requisitos. Sé que muchas personas se burlan de la idea de llevar a cabo el Análisis de requisitos en el desarrollo de una aplicación, pero sorprendentemente dicho documento responderá de manera concisa a qué y dónde debe dedicar sus recursos relacionados con el rendimiento a medida que la aplicación esté a punto de completarse. Y responderá a esa pregunta de manera oportuna
La documentación de requisitos le ahorrará cientos de horas de tiempo que de otra forma se desperdiciarían en procesos no esenciales.
fuente
Un enfoque equilibrado sería mejor. El rendimiento es importante pero no tan importante como hacer las cosas, así que:
Este es mi enfoque común para el rendimiento frente a la funcionalidad, y en casos generales todo depende de lo que hace el programa y de verificar si hay alguna necesidad de hacer que las cosas funcionen mejor y cuánto tiempo me costaría.
Pensemos en un sitio web de preguntas y respuestas como este, creo que los que están detrás de él seguramente pensaron mucho sobre cómo hacer una pregunta y obtener la respuesta con la mayor cantidad de tiempo / costo posible. Pero, al pensar en las notificaciones, realmente no importa mucho si las notificaciones aparecen de vez en cuando y le dicen que hay una nueva respuesta o algo así.
fuente
Hay una forma de diferir de manera segura el pensamiento sobre el rendimiento: usar lenguajes específicos de dominio siempre que sea posible.
Si la mayor parte de su desarrollo se puede hacer con sus propias pequeñas DSL, y están diseñadas lo suficientemente bien como para expresar su dominio del problema en la forma más genérica y de alto nivel, es posible obtener un prototipo funcional primero, sin pensar en rendimiento, y luego solo mejorará sus implementaciones de DSL, no el código de dominio del problema real.
Es un enfoque mucho mejor desde el punto de vista de la mantenibilidad también.
fuente
Debe tener en cuenta el rendimiento. Sin embargo, debe dibujar una línea para marcar el final de la afinación, ya que (generalmente) su tiempo es más importante que el de la computadora.
Un muy buen artículo de texto sobre rendimiento es: The Computer Performance Shell Game .
fuente
La "mejor" forma es un término muy cargado, y la respuesta puede depender en gran medida de factores desconocidos hasta el tiempo de ejecución.
La lista sigue y sigue.
Lo que puede hacer, es escribir "la cosa más simple que podría posiblemente el trabajo" de los conocimientos que actualmente no tienen, y hacerlo en un modular de la moda para que pueda reorganizar fácilmente cuando se sabe más. ¡Tenga en cuenta que lo "más simple" no es necesariamente simple!
fuente
Siempre es algo que debes tener en cuenta. Creo que lo que la mayoría de la gente intenta decir es que no tiene mucho sentido pasar dos días tratando de optimizar algo que ni siquiera sabe que está roto. Una vez que tenga un producto en funcionamiento y pueda hacer algunas pruebas de usabilidad, eso debería mostrarle dónde tiene problemas de rendimiento. Luego, una vez que pueda identificar los verdaderos problemas de rendimiento, puede orientar las optimizaciones que necesita realizar.
fuente
Al menos en teoría, debería comenzar a pensar en el rendimiento una vez que esté en la prueba beta y no antes.
Sin embargo, esto no es una licencia para tomar malas decisiones de diseño. Por ejemplo, el uso de una cadena NVARCHAR como clave principal es una ruta segura hacia un bajo rendimiento; Dicho esto, es un hábito sucio independientemente de los problemas de rendimiento y no debes usarlo en primer lugar.
Si su diseño sigue las mejores prácticas convencionales (todo en tercera forma normal, información adecuada que se oculta en sus clases, uso mínimo de singletons, etc.) y hay un problema de rendimiento más adelante, será fácil de manejar (cree un índice aquí, implementar un caché allí).
HTH
fuente
Depende. Es útil tener en cuenta la regla 80/20: la mayoría (digamos el 80%) del código en la aplicación nunca se ejecutará con la frecuencia suficiente para hacer una diferencia notable en el rendimiento. Debe centrarse en el 20% restante donde la aplicación gastará aproximadamente el 80% de su tiempo de ejecución.
Es posible que pueda identificar algunos de los puntos críticos de rendimiento obvios de antemano, como si supiera que un cálculo en particular se repetirá millones de veces. En tales casos, definitivamente vale la pena pensar en optimizarlo por adelantado al elegir las estructuras de datos y algoritmos correctos para el trabajo.
Sin embargo, esa optimización es más una actividad de diseño. Lo que generalmente no tiene valor son las micro optimizaciones, en las que alguien pasa una cantidad excesiva de tiempo con ingeniosos trucos para "tocar el rendimiento". Especialmente si se realiza sin mediciones apropiadas antes y después, dichos cambios pueden no hacer ninguna diferencia, o en realidad ralentizar la aplicación en circunstancias de la vida real.
fuente
Depende de en qué etapa de desarrollo se encuentre
1) Si construye la funcionalidad de su software, manténgalo en funcionamiento y asegúrese de que funcione bien (es decir, deseado y eficiente).
2) Una vez que se integran los bloques de construcción, obtendrá un indicio de acumulación de recursos, allí tiene espacio para la optimización.
fuente
Si tiene que comenzar a pensar en el rendimiento, está en problemas. Deberías estar pensando en el rendimiento todo el tiempo. De hecho, sospecho que los buenos programadores van a pensar en el rendimiento, incluso cuando no tenían la intención de hacerlo, de una manera «los hombres piensan en el sexo cada siete segundos».
Lo importante es qué acciones tomará en función de todo ese pensamiento. Los pensamientos son baratos, pero las acciones pueden romper el código y romper los plazos.
La mayoría de las veces, la única acción sensata será no hacer nada: identificó que su código no se llamará con la frecuencia suficiente para que los problemas de rendimiento sean observables, tal vez es un código de inicio que se ejecuta una vez por computadora para 1% de su base de usuarios potenciales, quizás sea un pequeño código de servidor redundante ahogado en un mar de accesos lentos a la base de datos, quizás sea solo una asignación de enteros en una sección de código no crítica.
Muy a menudo, sospecha que una operación determinada puede causar un problema de rendimiento que podría resolverse con un simple cambio. Existe, por ejemplo, la sensación persistente de que ejecutar una consulta SQL compleja en cada solicitud, o pedir dos veces el mismo dato de un diccionario, será malo para usted. Aquí es donde el conocimiento de las técnicas de optimización es útil, y quizás ocurra la conclusión más sorprendente:
Si conoce una técnica rápida que seguramente mejorará el rendimiento de un código, no lo haga.
Si puede pensarlo ahora, ciertamente puede hacerlo cinco minutos después. Mantenerlo fuera del código (pero, tal vez, en un
// TODO
comentario) deja el código más limpio y le ahorra tiempo anterior para trabajar en otra función, sin perder tiempo si termina desechando ese código más adelante. Si el código original causa problemas de rendimiento cuando se prueba, regrese y aplique su técnica rápida.No digo aquí que debas evitar escribir código que sea idiomático solo porque resulta ser más rápido. Escriba código idiomático de acuerdo con las mejores prácticas que mejoran la productividad y la legibilidad y reducen los errores. Es solo que si tiene que elegir entre un código idiomático por libro y una alternativa más rápida pero fácil de escribir, siempre busque legibilidad en lugar de velocidad.
La única situación difícil es cuando parece que no hay una manera fácil de mejorar el rendimiento del código y, sin embargo, es dolorosamente obvio que un fragmento de código se romperá tan pronto como se entregue: un recorrido completo de la base de datos en cada clic, cien solicitudes SQL por página en el sitio, o cualquier cosa igualmente terrible. Aquí es donde realmente necesitas detenerte y pensar un poco más. Por lo general, estos son problemas de arquitectura que no se pueden resolver a escala local de todos modos. Confirme sus sospechas con un pico o prototipo rápido, busque experiencias similares y soluciones comunes, y considere un cambio de arquitectura o una caída de características.
fuente
En mi humilde opinión, es importante pensar en el rendimiento antes de implementar el sistema, pero solo pensar en ello. Debe analizar la aplicación y descubrir cuáles podrían ser posibles cuellos de botella en el rendimiento.
Luego implemente el sistema lo más simple posible. Si surgen problemas de rendimiento, entonces optimice.
Por ejemplo, supongamos que tiene un cliente GUI que obtiene datos a través de algún tipo de servicio (SOAP, REST HTTP, etc.). Entonces, lo más importante para el alto rendimiento / escalabilidad es tener la menor cantidad de llamadas posible, haciendo que cada llamada devuelva muchos datos, en lugar de que muchas llamadas devuelvan poca información cada una, es decir, prefiera la comunicación fornida a lo hablador.
Al implementar este tipo de sistema, no me importaría mucho la cantidad de llamadas entre el sistema. Pero me aseguraría de que la base del código me facilitaría refactorizar / optimizar cuando surja la necesidad.
fuente
Debe pensar en el rendimiento de manera muy general desde el principio. Debe seleccionar estructuras de datos y algoritmos que funcionen bien para su aplicación y sean razonablemente eficientes. Los algoritmos son fundamentales para el software, y las estructuras de datos aún más. Es probable que tenga que realizar reescrituras importantes si necesita realizar cambios importantes en cualquiera de ellas, mientras que los detalles más pequeños se pueden reescribir más fácilmente.
Es posible que también desee adquirir hábitos eficientes, pero estos dependerán del idioma. En C ++, por ejemplo, "++ i;" como una declaración o expresión independiente siempre es al menos tan buena como "i ++;" y podría ser mucho más eficiente. Sin embargo, en la mayoría de los casos, debe escribir un código claro y confiar en el compilador. Tener el hábito de preocuparse por las microeficiencias seguramente le causará más problemas de los que resuelve. Para las aplicaciones de escritorio, el compilador es al menos tan inteligente como usted con respecto a cosas como
i >> 1
vs.i / 2
o la mejor manera de mejorar el rendimiento es obtener un mejor compilador, así que no se preocupe por eso.Más allá de eso, no te preocupes mucho hasta que tengas algo que puedas probar. En ese momento, puede perfilar el programa para ver dónde están los puntos críticos y, probablemente, tener una idea de si tiene un programa de rendimiento o no. Si necesita mejorar el rendimiento, averigüe dónde pasa el programa la mayor parte de su tiempo y mejore las cosas allí. Si ha diseñado con una eficiencia global adecuada y ha escrito bien el programa, solo está cambiando una parte relativamente pequeña del programa.
fuente
Creo que lo mejor que puede hacer es seguir las buenas prácticas de diseño (por ejemplo, no haga cosas que sepa que obstaculizarán el rendimiento) hasta que algo funcione. Si no puede medir la mejora, no puede hacer una mejora. Una vez que tenga algo con lo que pueda probar, a menudo es una buena idea realizar una ejecución de perfil y tener una idea de dónde están los puntos calientes (si los hay). Si algo te llama la atención, deberías considerar refactorizar o reescribir el área del problema, pero si no es tan malo (solo porque el código pasa el 90% de su tiempo en dos o tres métodos no significa nada si funciona adecuadamente en general) entonces solo sigue desarrollándote. Algo que he visto más de una vez son los desarrolladores que pasan días optimizando la parte más compleja del sistema,
fuente
¿Cuándo debería comenzar a pensar en ello? ¿Cuánto esfuerzo debería poner en ello? Eso depende de la escala Cockburn del proyecto. (En otras palabras, ¿cuál es el riesgo de no tener un buen rendimiento?)
Aprenda los fundamentos con bastante anticipación (vea la respuesta de Robert Harvey ). Para aplicar el pensamiento orientado al rendimiento durante varias etapas del desarrollo de software, el desarrollador debe conocerlo al revés, para que el proceso de pensamiento no se vea obstaculizado por esas consideraciones adicionales. (En otras palabras, comience a pensar en el rendimiento antes de concebir el proyecto).
Durante la primera etapa de desarrollo, haga un uso liberal de las herramientas de creación de perfiles de rendimiento y realice un seguimiento del historial de estadísticas. Preste especial atención a organizar dicha información para que sean útiles para la toma de decisiones posterior.
Luego, dependiendo de la naturaleza de su proyecto y su escala Cockburn:
Creación rápida de prototipos, o "código de salida como si no hubiera mañana", o desarrollo interno con bajo impacto comercial: solo guarde las estadísticas. No pienses en el rendimiento todavía. Implemente la función de la manera más fácil. Quédese con el primer algoritmo que se le ocurra.
Aplicaciones de escritorio, que requieren un enfoque de rendimiento consistente y completo. No tiene que estar altamente optimizado; sin embargo, debe haber la menor cantidad posible de "bloqueos" (falta de respuesta).
Computación de alto rendimiento, que requiere obtener el máximo rendimiento del hardware.
fuente
Al principio. Identificar las características de rendimiento requeridas. Si no puede identificar el objetivo, debe retroceder para comprender mejor sus requisitos o diferir hasta que conozca los requisitos de sus componentes con el riesgo de que pueda estar reescribiendo. Entonces, prueba. No optimices, prueba. Si el código falla la prueba de rendimiento, optimice. Con un marco de prueba establecido, el uso de las herramientas de monitoreo de rendimiento existentes debería facilitar la tarea de manera razonable.
Mantenga las pruebas de rendimiento en su lugar durante toda la vida del proyecto como prueba de regresión. El código de mantenimiento es conocido por provocar problemas de rendimiento porque las 'soluciones' a menudo tienen un enfoque muy limitado.
fuente
Siempre confío en una fórmula simple:
... en ese orden.
Según c2 , esta formulación se atribuye a Kent Beck .
fuente