¿Para qué se "optimizan" los programadores hoy? [cerrado]

14

En los "buenos tiempos", cuando copiamos shareware en disquetes para amigos, también usamos un poco de ensamblaje. Había una práctica común de "microoptimización", en la que mirabas fijamente y mirabas las líneas de ensamblaje hasta encontrar una manera de expresarlo en una instrucción menos. Incluso hubo un dicho, que era matemáticamente imposible, que " siempre se puede eliminar una instrucción más " . Dado que cambiar el rendimiento en tiempo de ejecución por pequeños factores constantes no es un problema importante para (la mayoría) de la programación actual, los programadores están transfiriendo estos micro- esfuerzos de optimización en otro lugar?

En otras palabras, ¿se puede llevar una mejor práctica a un estado extremo donde ya no agrega nada de valor? ¿Y en cambio está perdiendo el tiempo?

Por ejemplo: ¿Los programadores pierden tiempo generalizando métodos privados que solo se llaman desde un lugar? ¿Se pierde tiempo reduciendo los datos de casos de prueba? ¿Están los programadores (todavía) demasiado preocupados por reducir las líneas de código?

A continuación hay dos excelentes ejemplos de lo que estoy buscando: (1) Pasar tiempo buscando los nombres de variables correctos, incluso cambiando el nombre de todo; y (2) Eliminar incluso la duplicación de código menor y tenue.


Tenga en cuenta que esto es diferente de la pregunta " ¿Para qué optimiza? ", Porque estoy preguntando qué otros programadores parecen maximizar, con el estigma de estas optimizaciones "micro" y, por lo tanto, no un uso productivo del tiempo.

Macneil
fuente
@ Macneil, no sé para qué se optimizan otros programadores, pero no tengo mucho tiempo para eso. Mis compañeros de trabajo también están ocupados (solo mis 2 centavos).
Trabajo
@ Job: ¿Nunca has visto a alguien perder el tiempo cambiando el código sin motivo? Considérate afortunado. Hay dos excelentes ejemplos a continuación: nombres de variables y duplicación de código menor.
Macneil
1
La pregunta, como está redactada actualmente, es una mejora. No puedo eliminar el voto cerrado, pero desaparecerá en unos días. En realidad, la pregunta está atrayendo algunas respuestas bastante buenas.
Robert Harvey
1
Por cierto, cualquier mejor práctica se puede llevar a tal extremo que ya no produce valor.
Robert Harvey

Respuestas:

22

Formato de código

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.
JeffO
fuente
Ah, sí, los viejos tipos de variables y nombres de variables necesitan sus propias columnas en una serie de declaraciones de variables. Oh! ¡Olvidé la fila extra para el =y el cuarto para los inicializadores!
Macneil
[Maldición, votaría, pero mi límite diario se alcanza ...]
Macneil
3
Nuestros profesores nos obligaron a formatear el código para nuestras tareas de esta manera. Me tomó años deshacerme de este hábito.
Oliver Weiler
Oh querido. En otras respuestas me estaba riendo, pero esta realmente duele :-(
Steve314
2
+1 Una vez trabajé con una biblioteca donde el desarrollador se negó a hacer que su código fuera correcto porque arruinaba su código con formato de columna ...
Dean Harding
20

Solía ​​escribir mucho ensamblador en el día. No es solo que los compiladores hayan mejorado, sino que la mayoría del hardware ahora tiene mucha lógica dedicada a la ejecución de código fuera de orden. El verdadero micro problema es la programación, la mayoría de las instrucciones de la computadora toman varios relojes de máquina para producir un resultado, ¡y una carga de memoria que pierde memoria caché puede tomar varios cientos! Entonces, la idea era programar otras instrucciones para hacer algo útil, en lugar de esperar un resultado. Y las máquinas modernas pueden emitir varias instrucciones por período de reloj. Una vez que comenzamos a ejecutar HW fuera de orden, descubrí que tratar de obtener un gran rendimiento con la codificación manual se convirtió en un juego de tazas. Primero, el HW fuera de orden no ejecutará las instrucciones en su orden cuidadosamente elaborada, La nueva y elegante arquitectura HW ha reducido la penalización de la programación de software inóptima lo suficiente como para que el compilador generalmente esté dentro de un pequeño porcentaje de su rendimiento. También descubrí que los compiladores ahora estaban implementando trucos conocidos pero generadores de complejidad, como desenrollar, cargar el fondo, canalizar el software, etc. La conclusión es que tienes que trabajar muy duro, omite algunos de estos trucos y el compilador te gana. ¡Utilícelos todos y la cantidad de instrucciones de ensamblador que necesita aumentará varias veces!

Probablemente aún más importante, la mayoría de los problemas de rendimiento, no se trata de tasas de problemas de instrucción, sino de introducir los datos en la CPU. Como mencioné anteriormente, la latencia de la memoria ahora es de cientos de ciclos, y la CPU puede ejecutar varias instrucciones por período de reloj, por lo tanto, a menos que el programa, y ​​especialmente las estructuras de datos, estén diseñadas para que la tasa de aciertos de la caché sea extremadamente alta, la microtuning en la instrucción nivel no tendrá resultado. Al igual que los tipos militares dicen que los aficionados hablan de tácticas, los profesionales hablan de logística. La programación de rendimiento ahora es más del 90% de logística (datos móviles). Y esto es difícil de cuantificar, ya que la administración de memoria moderna generalmente tiene múltiples niveles de caché, y las páginas de memoria virtual son manejadas por una unidad de hardware llamada TLB. También la alineación de bajo nivel de las direcciones se vuelve importante, ya que las transferencias de datos reales no están en unidades de bytes, o incluso de 64 bits de largo, pero vienen en unidades de líneas de caché. Entonces, la mayoría de las máquinas modernas tienen hardware que intenta predecir qué línea de caché se pierde en un futuro cercano y emiten prefetches automáticos para llevarlos al caché. Entonces, la realidad es que con las CPU modernas, los modelos de rendimiento son tan complejos que son casi incomprensibles. Incluso los simuladores de hardware detallados nunca pueden coincidir con la lógica exacta de los chips, por lo que el ajuste exacto es simplemente imposible.

Todavía hay un lugar para algunas codificaciones manuales. Las bibliotecas matemáticas (como la función exp), al igual que las operaciones de álgebra lineal más importantes (como la multiplicación de matrices) todavía suelen estar codificadas manualmente por expertos que trabajan para el proveedor de hardware (es decir, Intel o AMD o IBM), pero probablemente solo necesita un par de programadores de ensamblador de primer nivel por cada megacomputadora.

Omega Centauri
fuente
1
La codificación manual es cada vez más difícil para las personas que trabajan fuera de los proveedores de CPU, ya que la tarea depende cada vez más del conocimiento interno y de las herramientas específicas del proveedor (compiladores y perfiladores). spiral.net intenta modelar la optimización de la CPU y automatizar la búsqueda de soluciones óptimas.
rwong
Muchos lenguajes de computadora empujan a los programadores a una micro-optimización sin sentido al dificultar el uso de doble precisión para los cálculos cuyos resultados se mostrarán float. Por alguna razón que no puedo entender, muchas personas piensan que esto es algo bueno.
supercat
10

A veces paso tiempo (¿pierdo?) Mientras elijo un buen nombre para una variable o un método, de modo que no solo sea descriptivo con precisión sino que también tenga un buen estilo lingüístico.

Va un poco más allá cuando intento poner todas las obras (un programa) en el mismo estilo lingüístico. A veces mi opinión cambia y reviso el libro. :)

No, eso lleva tanto tiempo. Es bastante raro. Pero me gusta mantener la buena gramática en mis programas.


fuente
3
Nombrar es difícil. Por lo tanto, debe refactorizar un nombre cuando piense en uno mucho mejor. Tenga en cuenta que esto captura el esfuerzo de la mente y, con suerte, cristaliza el "por qué" también.
1
Esto es en gran medida una cuestión de cerebro izquierdo (el lado izquierdo de su cerebro es responsable del procesamiento del lenguaje). Como programador con cerebro derecho, tiendo a pasar mucho menos tiempo preocupándome por la semántica y más tiempo preocupándome por cómo encajan todas las piezas.
Jason Baker el
77
El nombramiento de variables y métodos es una parte importante de la mantenibilidad. Uno debería pasar tiempo pensando en los nombres, de modo que dentro de 5 años, la persona que mantiene el código tenga más facilidad para hacerlo.
GrandmasterB
@grandmaster: No podría estar más de acuerdo.
Robert Harvey
44
@ right-brainers: codifique los lef-tbrainers, para que yo también pueda leer su código
Juan Mendes
10

Complejidad del tiempo. Paso demasiado tiempo optimizando las cosas para el peor de los casos en una escala que es mucho mayor que cualquier cosa que sé que el programa encontrará de manera realista.

Soy demasiado obsesivo para dejar ir el hueso 'pero podría crecer ese gran hueso', incluso cuando otras decisiones de diseño impiden que eso suceda de manera realista.

Sin embargo, en mi defensa, si lo poco realista se convierte en realidad ... la optimización realmente ya no es 'micro'. Tenga en cuenta que no dije imposible , pero poco realista .

Por supuesto, los requisitos tienen prioridad.

Tim Post
fuente
1
Trabajé para una empresa que se hundió por esto.
Henry
2
@Henry - Lo prometo, no fui yo :)
Tim Post
1
@Henry: ¿Quiere decir que desperdician tiempo en la optimización de las cosas que probablemente no volvería a ocurrir, o que no piensan acerca de las cosas que probablemente "nunca" pasar ... hasta que se hicieron pasar y ya era demasiado tarde?
Dean Harding
2
@Henry: si una empresa tiene un producto altamente escalable y aún así se hundió, es culpa de las ventas y el marketing (por no apuntar a clientes de gran volumen y no fijar los precios adecuadamente), no por el desarrollo.
rwong
1
La compañía pasó demasiado tiempo diseñando un sistema para millones de usuarios cuando no tenían 1 usuario. Debe haber sido culpa de marketing. Sí, culpemos al marketing, esos tipos son idiotas.
Henry
8

Creo que he perdido semanas de tiempo jugando con los controladores de excepciones de Java.

Esto es mucho trabajo para el código que falla dos o tres veces al año. ¿Debería ser esto una advertencia o una información? ¿Error o fatal? ¿Es realmente fatal si el proceso se volverá a generar en cinco minutos? ¿Es realmente una advertencia si todo sigue en estado predeterminado?

Muchas miradas en el ombligo y discusión sobre la naturaleza de un error IO. Si no puede leer un archivo a través de la red, ¿es un error de archivo o un error de red? Y así.

En un momento, reemplacé todas las cadenas de concat String.formatpara que el error de archivo anual no dé como resultado objetos adicionales en el montón. Eso fue un desperdicio.

sal
fuente
3
Este es un trabajo importante. El precio de la falla = su mensaje de error aparece en el WTF diario.
Steve314
7

Supongo que estoy demasiado preocupado por los LOC. No tanto los LOC en sí mismos, sino más bien el número de declaraciones e incluso más número de declaraciones duplicadas. Soy alérgico al código duplicado. En general, me encanta la refactorización, pero supongo que aproximadamente el 50% de lo que hago no hace que el código sea significativamente mejor.

back2dos
fuente
44
+1 para "Soy alérgico al código duplicado". Vea también mi respuesta aquí: programmers.stackexchange.com/questions/14610/…
Macneil
Pensando en ello: tengo este problema con los bucles que se relaciona con un punto que Knuth hizo sobre goto, y a veces tener que intercambiar un ciclo o dos o algún código duplicado para escribir código estructurado. Yo voy a usar un Goto en casos muy raros (más común = código generado), pero mi variación de este trastorno es la pérdida de tiempo de preocuparse y jugando con un bucle sin fin tratar de eliminar una ineficiencia trivial sin embargo, mantener el código legible.
Steve314
5

Leer un archivo línea por línea en lugar de simplemente leer la línea completa en una cadena y procesar la cadena de una sola vez.

Claro, hace una diferencia en la velocidad de ejecución, pero rara vez vale la pena las líneas adicionales de código. Hace que el código sea mucho menos mantenible y aumenta el tamaño del código.

Sí, esto probablemente no tiene sentido si el archivo es de 3 GB pero la mayoría de los archivos no son tan grandes (al menos no con los que estoy trabajando ;-)).

Oliver Weiler
fuente
3
Incluso si es 3GB o más, una máquina de 64 bits puede manejarlo con memoria virtual. Use un archivo mapeado de memoria y ni siquiera leerá ninguna parte de su archivo hasta que sea necesario. Eso sí, incluso eso es micro-optimización en el caso normal.
Steve314
3

Cuando estaba escribiendo lenguaje ensamblador, tenía sentido analizar minuciosamente los bytes y los ciclos, pero eso fue hace mucho tiempo y los compiladores han recorrido un largo camino desde entonces. No intentaría optimizar manualmente uno ahora.

Del mismo modo, cuando cambié a escribir en C, fue bastante fácil hacer un mejor trabajo que los compiladores de C, pero cada año Borland, Microsoft o alguien lanzaría uno nuevo y mejorado que pateaba el anterior por la sala. Comencé a prestar atención al código de ensamblaje real que emitía el compilador y me arriesgué si no estaba escribiendo un código agradable y ajustado, desenrollando bucles, moviendo variables fuera de los bucles, etc.

Hoy en día estoy escribiendo en idiomas mucho más altos como Perl, Python y Ruby. Utilizo algunos de los trucos del compilador por adelantado, como desenrollar bucles si tiene sentido, mover variables estáticas fuera de los bucles, etc., pero no me preocupa tanto porque las CPU son un poco más rápidas ahora. Si una aplicación parece arrastrarse inesperadamente, usaré un generador de perfiles y veré qué puedo encontrar, y luego, si se puede mejorar algo, comenzaré a comparar varias formas en que puedo pensar para hacer algo más rápido, y luego veré cómo funciona. escala hacia arriba.

En general trato de ser inteligente en la forma en que escribo el código, basado en años de experiencia.

el hombre de hojalata
fuente
Hola Greg, gracias por la respuesta, pero estoy buscando lo que hacen los programadores para perder el tiempo, no para optimizar el rendimiento del tiempo de ejecución. Hay dos excelentes ejemplos anteriores: nombres de variables y eliminar incluso duplicaciones de código menores.
Macneil
3

Una microoptimización: mejorar el rendimiento de un solo subproceso de cosas que son paralelizables o que simplemente se pueden mejorar con nuevo hardware.

Si algo es lento en una computadora de hace 10 años, una solución más barata es probablemente comprar una computadora más nueva y más rápida, en lugar de perder el tiempo de optimización del programador. Sin embargo, un gran enfoque de las optimizaciones consideradas debería ser encontrar una manera de usar los 8 núcleos que puede obtener hoy, o los 64 que podrá obtener en un par de años, en lugar de agonizar por minucias como el costo adicional de la basura colección.

Kevin Cantu
fuente
2

La microoptimización en términos de rendimiento en tiempo de ejecución no es un problema cerrado incluso hoy (aunque podría ser menos común). De vez en cuando tengo que explicar a las personas que la sobrecarga de asignar un objeto adicional a cada solicitud o agregar una llamada de función adicional es insignificante.

Aparte de eso, también veo a los programadores micro-optimizados por simplicidad (incluido yo mismo). Todavía tengo que trabajar en algún lugar que no tenga que explicar la diferencia entre simplicidad y simplicidad.

Jason Baker
fuente
¿Por qué los programadores? ser diferente? ¿Cuál es la diferencia, por favor?
Dan Rosenstark el
@Yar - ¿Por qué los programadores serían diferentes de qué?
Jason Baker, el
¿por qué programmers.= programmers.stackexchange.comser diferente de todos los lugares que usted ha trabajado en el que ha tenido que explicar la diferencia entre estos dos conceptos? Por favor explique la diferencia.
Dan Rosenstark
@Yar - No sé si lo haría. De hecho, como el objetivo de programmers.se es ayudar a los programadores a unir conocimientos, espero que no sea así para que la gente se ilumine al menos un poco con mi respuesta.
Jason Baker, el
2
Entonces, ¿cuál es la diferencia entre simplicidad y simplicidad?
Dan Rosenstark
2

Estoy a favor del principio de no optimizar, a menos que sea realmente necesario. Y estoy totalmente de acuerdo con el principio de primer perfil. Y, en principio, solo optimizaré algo que haga la diferencia necesaria.

Eso es en principio. Pero el principio es un mentiroso.

Tengo la costumbre de cuidar las funciones en las bibliotecas de uso frecuente que creo que se usarán mucho en los bucles internos. Y luego, cuando ves algo en otra función, eso no se usa con tanta frecuencia ...

Ah, y luego está la lógica "Lo estoy escribiendo, por supuesto que es una biblioteca importante".

Ah, y por cierto. Nunca he usado un perfilador para guiar una optimización. No tengo acceso a uno comercial, y nunca creé la motivación para descubrir gprof.

Básicamente, soy un hipócrita. Estos principios se aplican a otras personas, pero tengo demasiado miedo de que alguien diga "pero ¿por qué lo escribiste de esa manera lenta y horrible?" así que nunca puedo aplicarlos correctamente a mí mismo.

Sin embargo, no soy tan malo como lo hago aquí. Y soy completamente inmune al autoengaño, ¡así que sabes que tengo razón en eso!

EDITAR

Debo agregar: uno de mis principales estupideces son los gastos generales de llamadas. No en todas partes, por supuesto, pero en esos casos de "creo-que-se-usará-mucho-en-bucles internos" (donde no tengo evidencia objetiva de un problema). He escrito código desagradable basado en offsetof para evitar hacer llamadas a métodos virtuales más de una vez. El resultado puede incluso ser más lento, ya que probablemente no es un estilo de codificación que los optimizadores están diseñados para manejar bien, pero es más inteligente ;-)

Steve314
fuente
+1 ¡Ah, sí! Esta clase analiza los argumentos de línea de comandos altamente específicos y peculiares de mi aplicación, pero déjame formatearla y documentarla completamente cuando Javadoc, porque seguramente otros lo usarán durante años. [Necesitaré votar más tarde, se alcanza mi límite diario].
Macneil
@ Macneil: eso es Doxygen, quiero que lo sepas. Con cada opción que puedo encontrar activada, cada pequeña función se "documenta" con detalles insoportables, completa con una docena de bonitos gráficos GraphViz. Realmente ayuda a todos a apreciar cuán importante es mi código, y la impresión puede empapelar un bloque de oficinas bastante grande.
Steve314
1

En los viejos tiempos, cuando las computadoras tenían tiempos de reloj medidos en microsegundos, memoria medida en kilobytes y compiladores primitivos, la micro-optimización tenía algún sentido.

La velocidad y el tamaño de las computadoras de la generación actual y la calidad de los compiladores de la generación actual significan que la microoptimización suele ser una pérdida total de tiempo. Las excepciones tienden a ser cuando tiene que obtener el máximo rendimiento de algún código computacionalmente intensivo ... o cuando está escribiendo para un sistema integrado con recursos extremadamente limitados.

pero estoy buscando lo que hacen los programadores para perder el tiempo, no para optimizar el rendimiento del tiempo de ejecución.

Twitter y Facebook vienen a la mente :-)

Stephen C
fuente
Hola Stephen, ese es un gran comentario sobre la microoptimización, pero ¿ves algún equivalente moderno? [Facebook y Twitter no son "mejores prácticas" que pueden llevarse demasiado lejos.]
Macneil
Todavía tiene sentido. Los tiempos de reloj pueden ser de órdenes de magnitud más pequeños, pero el código es de órdenes de magnitud más grandes ...
hplbsh
@Stuart: eso significa que hay órdenes de magnitud más código para micro-optimizar ... que simplemente no escala.
Stephen C