it-swarm-es.com

¿Cuándo debería preocuparme por el rendimiento?

Durante mucho tiempo en lugares como Java IRC canal , SO, y otros lugares me han dicho algo como "Preocuparse por cómo se ve el código y su legibilidad/comprensibilidad ahora, y rendimiento más tarde si es absolutamente necesario ". Por lo tanto, durante mucho tiempo, no he sido realmente obsesivo con el rendimiento de mis pequeñas aplicaciones de escritorio o web, simplemente eliminando 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 fue creada 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 introducir 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 por grandes bestias gigantes complicadas que hacen las cosas extremadamente rápido pero destruyen cualquier forma posible de actualización y hacen que el código sea excesivamente difícil y propenso a ser reescrito por el próximo desarrollador?

16
TheLQ

Preocúpese por el rendimiento cuando se convierta en un problema.

Si escribe una aplicación pequeña para procesar 10,000 archivos de línea y obtiene un archivo de 1,000,000 de líneas cada archivo número 100, probablemente no importa que se tarde más en procesar ese archivo. Sin embargo, si regularmente obtiene archivos que son 5-10 veces más grandes que inicialmente y su aplicación tarda demasiado en hacer su trabajo, entonces comience a crear perfiles y optimizar.

Ahora, dije "demasiado tiempo para hacer su trabajo". Eso es decisión del usuario o de la organización patrocinadora. Si estoy haciendo una tarea y me toma 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 quiere que se haga más rápido o si está dispuesto a esperar más para tener un código más legible.

23
Thomas Owens

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

Suele ser una falsa dicotomía . Puede escribir código maravillosamente eficiente, legible y fácil de mantener. Puedes escribir pilas de desorden maravillosamente ineficientes e inmateriales.

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

10
Sam Saffron

Una obviedad que aprendí al estudiar microprocesadores en la universidad y que se quedó conmigo: "Haz que el caso común sea rápido. Haz que el caso poco común sea correcto".

Siempre que tenga solo un pequeño porcentaje de usuarios ahogando su código con una entrada dos órdenes de magnitud más grande de lo que estaba destinado a manejar, no se preocupe. Asegúrese de que maneja la entrada correctamente si le dan el tiempo suficiente y de que no deje nada corrompido en la inutilidad si matan el trabajo antes de que finalice.

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

5
BlairHippo

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

"Preocuparse por cómo se ve el código y su legibilidad/comprensibilidad ahora, y el rendimiento más tarde 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 lío, fuerza las actualizaciones en sus clientes, a menos que sea demasiado tiempo para que se actualicen. ese programa lento se convierte en un gran lío que es demasiado costoso de mejorar. luego eligen una alternativa porque no se adapta 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 para escribirlo para que sea eficiente, funcione correctamente y tenga un buen diseño en general. ese programa es altamente reutilizable y requiere poco mantenimiento (win).

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

tenga en cuenta y evite los diseños innecesarios al escribir programas de producción y programas que desea 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 de arreglar después de que está escrito. Mucha gente cree que un poco de perfilado (tal vez) al final o si hay un problema es adecuado, cuando por lo general lleva demasiado tiempo rediseñar/cambiar y las ineficiencias son tantas y tan generalizadas que no se entiende 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) normalmente da como resultado un diseño que es varias veces más rápido y es reutilizable en muchos más contextos. no desperdiciar, elegir buenos algoritmos, pensar en sus implementaciones y reutilizar las implementaciones correctas son todos componentes de un buen diseño; todo lo cual mejora legibilidad, mantenibilidad y reutilización con más frecuencia de lo que lo perjudica.

1
justin

Si está trabajando en áreas realmente críticas para el rendimiento, no puede dejar de lado la eficiencia como una ocurrencia tardía. Es una de las cosas más críticas en las que pensar al diseñar desde el principio en esos casos y en formas que se relacionan con la capacidad de mantenimiento 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 usa funciones de bloqueo para todo con un bloqueo de hilo global que bloquea todo el sistema para procesar cada solicitud de cliente individual sin poner ninguna. pensamiento en absoluto en estado compartido, contención de hilos y asincronicidad. Esta 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 intentarlo. para lograr la eficiencia requerida en retrospectiva, en lugar de haber pensado en diseños eficientes, simples y funcionales desde el principio.

Un equipo de desarrollo de juegos que lleva 8 meses en producción con un motor que solo funciona a 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 instantáneamente un producto utilizable simplemente arreglando un pequeño punto de acceso localizado. Lo más probable es que su diseño sea FUBAR de manera que justifique una revisión épica del tablero de dibujo y cambios de diseño que podrían caer en cascada en cada rincón del código base.

Con John Carmack, habló una vez sobre cómo una demostración técnica debe ejecutarse a un mínimo de cientos o miles de fotogramas por segundo para integrarla en la producción. Esa no es una obsesión malsana con la eficiencia. Él sabe de antemano que los juegos deben ejecutarse, en su totalidad, a más de 30 FPS para que los clientes lo consideren aceptable. Como resultado, un pequeño aspecto como un sistema de sombra suave no se puede ejecutar a 30 FPS, o de lo contrario, 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 áreas de rendimiento crítico donde existe un requisito fundamental para la eficiencia, una solución que no logra la velocidad adecuada no es mejor que una que no funciona en absoluto, ya que ambos son completamente inutilizables. Y no puede diseñar un sistema de sombra suave eficiente que se ejecute a cientos o miles de fotogramas por segundo como se requiere para un motor de juego en tiempo real a menos que piense de manera predominante en cuanto a su eficiencia. De hecho, en tales casos, más del 90% del trabajo se orienta en torno a la eficiencia, ya que es trivial crear un sistema de sombra suave que funcione bien a 2 horas por fotograma utilizando el trazado de ruta, pero no puede esperar ajustarlo. a correr a cientos de fotogramas por segundo sin un cambio de enfoque totalmente diferente.

Cuando la eficiencia es una parte fundamental del diseño de una aplicación, no se puede esperar lograr la eficiencia en retrospectiva sin perder drásticamente más tiempo del que ahorró al ignorarlo, ya que no se puede esperar lograr un diseño funcional en retrospectiva. Nadie dice, "yo está bien dejar de pensar en el diseño para más tarde. Simplemente documente bien su código y podrá crear un diseño adecuado más tarde". Pero en arquitecturas de rendimiento crítico, eso es lo que está haciendo efectivamente si no pone mucho cuidado y pensamiento en diseños eficientes desde el principio.

Ahora, eso no significa que tenga que microajustar sus implementaciones de inmediato. Para los detalles de implementación, hay mucho espacio para iterar hacia soluciones más rápidas después de la medición, siempre que no sea necesario cambiar el diseño 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 cambia el diseño. Y si un diseño tiene el requisito de ser razonablemente eficiente o, en algunos casos, 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 trazadores de rayos o motores de juegos o motores físicos, las ideas 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 desde el principio. Fue colocar ese pensamiento exactamente en el momento más productivo para hacerlo, y desde el principio.

0
user204677

Intento hacer que el código sea legible, al diablo con el rendimiento.

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
Josip Medved

Um - ¿Nunca?

En serio, el código siempre debe escribirse de manera que se pueda entender y mantener fácilmente.

Con respecto a cuándo lidiar con los problemas de rendimiento, resuélvalos 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 de manera que sea claro, conciso, comprensible y fácil de mantener, entonces usted u otro programador no deberían tener problemas para refactorizar el código para hacerlo más eficiente.

0
Noah Goodrich

Normalmente escribo código para que sea 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 acostumbrarse a realizar optimizaciones comunes que no afecten la legibilidad de su código. Es decir, si un fragmento de código se puede escribir de dos maneras igualmente (o casi igualmente) legibles, elija la que sea más rápida.

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

De manera similar, los tipos de datos inmutables tienden a ser más rápidos que los mutables, por lo que utilizo tipos de datos inmutables donde puedo.

0
Chinmay Kanchi