¿Cuándo debería importarme el rendimiento?


16

Durante mucho tiempo en lugares como el canal IRC de Java , SO y otros lugares, me han dicho algo como "Preocúpate por cómo se ve el código y su legibilidad / comprensibilidad ahora, y el rendimiento más tarde si es absolutamente necesario". Por lo tanto, durante mucho tiempo, realmente no he tenido un TOC sobre el rendimiento de mis pequeñas aplicaciones de escritorio o web, solo eliminé lo obviamente ineficiente.

La mayoría de las respuestas son "¿Qué pasa con la escalabilidad?". Ese es un punto legítimo, pero si mi aplicación solo se creó para analizar, digamos, archivos de 10,000 líneas de largo, ¿debería hacer que mi código sea un desastre para el pequeño porcentaje de personas que van a meter un archivo de 1,000,000 de líneas?

Mi pregunta principal es ¿cuándo debería cambiar las formas fáciles pero algo ineficientes de hacer tareas para grandes bestias gigantes y complicadas que hacen las cosas extremadamente rápido pero destruyen las posibles formas de actualización y hacen que el código sea excesivamente difícil y propenso a ser reescrito por el próximo desarrollador?

Respuestas:


23

Preocuparse por el rendimiento cuando se convierte en un problema.

Si escribe una pequeña aplicación para procesar archivos de 10,000 líneas y obtiene un archivo de 1,000,000 de líneas cada 100, probablemente no importa que tome más tiempo procesar ese archivo. Sin embargo, si regularmente obtiene archivos que son 5-10 veces más grandes que inicialmente y su aplicación está tardando demasiado en hacer su trabajo, entonces comienza a perfilar y optimizar.

Ahora, dije "demasiado tiempo para hacer su trabajo". Eso depende del usuario o la organización patrocinadora para decidir. Si estoy haciendo una tarea y me lleva 5 minutos hacer algo cuando me tomó 3 sin el software o con una herramienta diferente, probablemente presentaría un informe de error o una solicitud de mantenimiento para mejorarlo.

Si usted es el usuario, depende de usted cuánto tiempo desea que su software haga su trabajo; solo usted puede decidir si desea que se haga más rápido o si está dispuesto a esperar más tiempo para tener un código más legible.



Comienzo a perfilar y optimizar Si 1) el trabajo lleva mucho tiempo 2) uno de los recursos de hardware está al máximo (por ejemplo, 100% de CPU)
A. Binzxxxxxx

10

Mi pregunta principal es ¿cuándo debería cambiar las formas fáciles pero algo ineficientes de hacer tareas para grandes bestias gigantes y complicadas que hacen las cosas extremadamente rápido pero destruyen las posibles formas de actualización y hacen que el código sea excesivamente difícil y propenso a ser reescrito por el próximo desarrollador?

Esto suele ser una dicotomía falsa . Puede escribir código maravillosamente eficiente, legible y mantenible. Puedes escribir montones de desorden maravillosamente ineficientes e imposibles de mantener.

Cuando trato con problemas de rendimiento, generalmente trato de pensar en el problema comercial que estoy resolviendo. ¿Cómo se comportará mi software cuando mis clientes lo usen? ¿El rendimiento de mis aplicaciones hará feliz a Jacob Nielsen ?


55
++ DICOTOMÍA FALSA! ¿Nunca aprenderán? Cuando encuentra y soluciona un problema de rendimiento, el código no solo es más rápido, sino que es mejor . ¡Solo me arrepiento de tener solo un voto a favor!
Mike Dunlavey

+1 por escribir que, por lo general, es una dicotomía falsa ... no siempre, pero generalmente.
Dan Rosenstark

1
-1 para escribir suele ser una falsa dicotomía; de hecho, suele ser correcta, y solo en casos excepcionales una falsa dicotomía. En más de 30 años de mi carrera de programación, he visto demasiadas optimizaciones de rendimiento "bien intencionadas" que, de hecho, hicieron que el código fuera más difícil de entender y mantener (y a menudo optimicé algo que era totalmente innecesario).
Doc Brown

5

Una verdad que aprendí estudiando microprocesadores en la universidad que se quedó conmigo: "Haga el caso común rápido. Haga que el caso poco común sea correcto".

Mientras tenga solo un pequeño porcentaje de usuarios que ahogan su código con una entrada de dos órdenes de magnitud más grande de lo que estaba destinado a manejar, no se preocupe. Asegúrate de que maneja la entrada correctamente si la dan durante el tiempo suficiente y no deja nada corrupto en inutilidad si mata el trabajo antes de que termine.

Pero, una vez más y más personas comienzan a usarlo de esa manera (o comienzan a decirte "Sabes, me encantaría usar esa herramienta que escribiste en mis informes semanales de TPS, pero toma todo el día"), ahí es cuando comienzas a considerar cambiar la facilidad de mantenimiento por ganancias de rendimiento.


1

Mi pregunta principal es ¿cuándo debería cambiar las formas fáciles pero algo ineficientes de hacer tareas para grandes bestias gigantes y complicadas que hacen las cosas extremadamente rápido pero destruyen las posibles formas de actualización y hacen que el código sea excesivamente difícil y propenso a ser reescrito por el próximo desarrollador?

"Preocuparse por el aspecto del código y su legibilidad / comprensibilidad ahora, y el rendimiento más adelante si es absolutamente necesario" es la salida fácil, y generalmente inútil. Un buen diseño será fácil de mantener, fácil de leer y eficiente.

El rendimiento es un componente común de un buen diseño. Si su programa es lento y derrochador, realmente no es reutilizable. cuando necesita arreglar ese desastre, fuerza las actualizaciones en sus clientes, a menos que sea demasiado tiempo para que ellos actualicen. ese programa lento se convierte en el gran desastre que es demasiado costoso para mejorar. luego eligen una alternativa porque no se ajusta a sus necesidades. El diagnóstico, la actualización y el tratamiento de los efectos secundarios de las mejoras en un mal diseño a menudo superan el tiempo de desarrollo inicial de escribirlo para que sea eficiente, funcione correctamente y tenga un diseño generalmente bueno. ese programa es altamente reutilizable y requiere poco mantenimiento (win).

por lo tanto, la respuesta corta a su pregunta es "no sea un desperdicio. Escriba para reutilizar. Está bien ser flojo al crear prototipos / desarrollar pruebas de conceptos, pero no use ese prototipo para el código de producción".

tenga en cuenta y evite diseños innecesarios al escribir programas de producción y programas que pretende reutilizar. durante la implementación es el momento ideal para escribir su programa para que no sea un desperdicio: tiene una idea clara de los detalles y su funcionamiento, y es realmente doloroso e ineficaz solucionarlo después de que se haya escrito. mucha gente cree un poco de elaboración de perfiles (tal vez) al final o si hay un problema es un adequete, cuando generalmente es demasiado tiempo para rediseñar / cambiar y las ineficiencias son tantas y tan generalizadas que no comprende el programa bien basado en los resultados de un perfil. Este enfoque lleva poco tiempo durante la implementación y (suponiendo que lo haya hecho suficientes veces) generalmente da como resultado un diseño que es varias veces más rápido y es reutilizable en muchos más contextos. no ser derrochador elegir buenos algoritmos, pensar en sus implementaciones y reutilizar las implementaciones correctas son todos componentes de un buen diseño; todos los cualesmejora la legibilidad, la mantenibilidad y la reutilización con más frecuencia de lo que perjudica.


0

Trato de hacer que el código sea legible: el rendimiento está condenado

Cuando, y si, el código resulta ser demasiado lento, lo refactorizaré para que sea más rápido. Por lo general, el proceso de refactorización se sigue con muchos comentarios, ya que el código tiende a ser menos legible.


0

¿Nunca?

En serio, el código siempre debe escribirse para que sea fácil de entender y mantener.

Con respecto a cuándo lidiar con los problemas de rendimiento, trátelos una vez que los identifique, no optimice previamente su código porque entonces solo estará adivinando dónde están los problemas de rendimiento.

Si su código está escrito para que sea claro, conciso, comprensible y fácil de mantener, usted u otro programador no deberían tener problemas para refactorizar el código para hacerlo más eficiente.


3
No estoy de acuerdo con esto Un requisito de rendimiento es un requisito no funcional válido para un sistema.
Thomas Owens

Técnicamente, si hay un requisito relacionado con el rendimiento claramente definido, se podría decir que ha identificado un problema de rendimiento y que debe tenerlo en cuenta en su solución. De lo que estoy hablando es de ser inteligente de antemano para que pueda evitar problemas 'potenciales' no específicos.
Noah Goodrich

Ah Sí, tienes toda la razón en ese caso. No te preocupes por las posibilidades porque hay muchas, pero concéntrate en lo que sabes.
Thomas Owens

0

Normalmente escribo código para ser legible en primer lugar. Si, y solo si, encuentro que el programa se ejecuta demasiado lento para hacer su trabajo, perfilo y optimizo. Dicho esto, no hay nada de malo en adquirir el hábito de realizar optimizaciones comunes que no afecten la legibilidad de su código. Es decir, si un código puede escribirse de dos maneras legibles (o casi igualmente), elija la que sea más rápida.

Por ejemplo, en Python, las comprensiones de listas (o expresiones generadoras) tienden a ser más rápidas que el forbucle equivalente , por lo que utilizo las comprensiones de listas donde puedo, si no afectan la legibilidad (por ejemplo, no anido las comprensiones de listas si Puedo evitarlo y usar un bucle for porque las comprensiones de listas anidadas pueden ser difíciles de analizar mentalmente).

Del mismo modo, los tipos de datos inmutables tienden a ser más rápidos que los mutables, por lo que uso tipos de datos inmutables donde puedo.


0

Si está trabajando en áreas realmente críticas para el rendimiento, entonces no puede posponer la eficiencia como una ocurrencia tardía. Es una de las cosas más importantes en las que pensar cuando se diseña desde el principio en esos casos y en formas que se relacionan con la mantenibilidad del resultado final.

No puede diseñar e implementar un servidor a gran escala y simplemente comenzar a escribir código fácil y bien documentado que solo utiliza funciones de bloqueo para todo con un bloqueo global de subprocesos que bloquea todo el sistema para procesar cada solicitud individual del cliente sin poner ningún pensado en estado compartido, contención de hilos y asincronía. Tal es una receta para el desastre y la necesidad de rediseñar y reescribir la mayor parte del código bien documentado que escribió de manera que podría conducir a la base de código más difícil de mantener imaginable, plagada de condiciones de carrera y puntos muertos como resultado de intentar para lograr la eficiencia requerida en retrospectiva, en lugar de haber pensado en diseños eficientes, simples y funcionales por adelantado.

Un equipo de desarrollo de juegos a los 8 meses de producción con un motor que solo pasa 2 cuadros por segundo en su hardware más robusto con 32 núcleos, mientras que tiene una tendencia a detenerse durante 15 segundos cada vez que la pantalla se llena, es poco probable que obtenga un producto utilizable de forma instantánea con solo arreglando un pequeño punto de acceso localizado. Lo más probable es que su diseño sea FUBAR de formas que justifiquen una revisión épica del tablero de dibujo y cambios de diseño que podrían caer en cascada en cada esquina de la base de código.

Con John Carmack, habló una vez sobre cómo una demostración tecnológica debe ejecutarse a un mínimo de cientos a miles de cuadros por segundo para integrarla en la producción. Esa no es una obsesión poco saludable con la eficiencia. Él sabe por adelantado que los juegos deben ejecutarse, en su totalidad, a más de 30 FPS para que los clientes lo encuentren aceptable. Como resultado, un pequeño aspecto como un sistema de sombra suave no puede ejecutarse a 30 FPS, o el juego en su conjunto no puede ser lo suficientemente rápido como para proporcionar la retroalimentación requerida en tiempo real. Es inutilizable hasta que logre la eficiencia requerida. En esas áreas críticas de rendimiento donde hay un requisito fundamental para la eficiencia, una solución que no logra alcanzar la velocidad adecuada en realidad no es mejor que una que no funciona en absoluto,. Y no puede diseñar un sistema eficiente de sombras suaves que se ejecute a cientos o miles de cuadros por segundo como se requiere para un motor de juego en tiempo real, a menos que ponga una cantidad predominante de pensamiento por adelantado en cuanto a su eficiencia. De hecho, en tales casos, más del 90% del trabajo está orientado a la eficiencia, ya que es trivial crear un sistema de sombra suave que funcione bien a las 2 horas por cuadro utilizando el trazado de ruta, pero no puede esperar ajustarlo. para correr a cientos de cuadros por segundo sin un cambio de enfoque totalmente diferente.

Cuando la eficiencia es una parte fundamental del diseño de una aplicación, no puede esperar lograr eficiencia en retrospectiva sin perder dramáticamente más tiempo del que ahorró al ignorarla, ya que no puede esperar lograr un diseño funcional en retrospectiva. Nadie dice: " está bien posponer pensar en el diseño hasta más tarde. Simplemente documente bien su código y podrá encontrar un diseño adecuado más adelante ". Pero en arquitecturas de rendimiento crítico, eso es lo que está haciendo efectivamente si no pone mucha atención y pensamiento en diseños eficientes por adelantado.

Ahora, eso no significa que deba microajustar sus implementaciones de inmediato. Para detalles de implementación, hay mucho espacio para iterar hacia soluciones más rápidas después de medir, siempre que el diseño no tenga que cambiar y, a menudo, esa es la forma más productiva de hacerlo. Pero a nivel de diseño, significa que debe pensar lo suficiente en cómo el diseño y la arquitectura se relacionarán con la eficiencia desde el principio.

La diferencia clave aquí es diseño.. No es fácil hacer grandes cambios en los diseños en retrospectiva, ya que los diseños acumulan dependencias, y las dependencias se romperán si el diseño cambia. Y si un diseño tiene el requisito de ser razonablemente eficiente o, en algunos casos, que su calidad se mide en gran medida por su eficiencia, entonces no debe esperar poder lograr un diseño adecuado como una ocurrencia tardía. Con cualquier producto competitivo donde la eficiencia es un gran aspecto de la calidad, ya sean sistemas operativos o compiladores o procesadores de video o raytracers o motores de juegos o motores de física, las reflexiones sobre la eficiencia y las representaciones de datos se pensaron meticulosamente desde el principio. Y en esos casos, no es una optimización prematura pensar tanto en la eficiencia por adelantado. Estaba colocando tal pensamiento exactamente en el momento más productivo para hacerlo,

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.