¿Qué es lo que los programadores "micro-optimizan" para hoy? [cerrado]

12

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 mirar y mirar las líneas de montaje hasta que descubriera una forma de expresarlo en una instrucción menos. Incluso hubo un dicho, que era matemáticamente imposible, de que " Siempre puedes eliminar una instrucción más. " Dado que el cambio en 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 en la actualidad. ¿Están los programadores transfiriendo estos esfuerzos de microoptimización a otro lugar?

En otras palabras, ¿Se puede llevar una mejor práctica a un estado extremo en el que ya no agregue nada de valor? Y, en cambio, es perder el tiempo?

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

Hay dos grandes ejemplos de lo que estoy buscando a continuación: (1) Dedicar tiempo a encontrar los nombres de variables correctos, incluso cambiar 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 que se trata de optimizaciones" micro ", y por lo tanto no es un uso productivo del tiempo.

    
pregunta Macneil 28.11.2010 - 00:56

12 respuestas

22

Formato de código

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.
    
respondido por el JeffO 28.11.2010 - 15:22
20

Solía escribir un montón de ensamblador en el día. No es solo que los compiladores hayan mejorado, es que la mayoría del hardware ahora tiene mucha lógica dedicada a la ejecución de código fuera de orden. El problema real es la programación, la mayoría de las instrucciones de la computadora toman varios relojes de la máquina para producir un resultado, ¡y una carga de memoria que pierde el caché puede tomar varios cientos! Así que 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 periodo 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ía las instrucciones en su orden cuidadosamente diseñado, la nueva y elegante arquitectura de HW ha reducido la penalización de la programación inoptima de software lo suficiente como para que el compilador estuviera generalmente dentro de un pequeño porcentaje de su rendimiento. También descubrí que los compiladores ahora estaban implementando trucos bien conocidos pero que generan complejidad, como desenrollarlos, cargarlos por el fondo, canalizar el software, etc. La conclusión es que tienes que trabajar muy duro, omitir algunos de estos trucos y el compilador te gana. ¡Utilícelos todos y el número de instrucciones del ensamblador que necesita se multiplicará 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 obtener 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 que a menos que el programa, y especialmente las estructuras de datos, estén diseñados de modo que la tasa de aciertos de caché sea extremadamente alta, el microtuning en el nivel de instrucción no tendrá ningún beneficio. Al igual que Los tipos militares dicen que los aficionados hablan de tácticas, los profesionales hablan de logística. La programación del rendimiento es ahora más del 90% de logística (datos en movimiento). 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 direcciones de bajo nivel se vuelve importante, como datos reales Las transferencias no están en unidades de bytes, ni siquiera en 64 bits de largo a largo, sino que vienen en unidades de lineas de caché. Entonces, la mayoría de las máquinas modernas tienen hardware que intenta predecir qué líneas de caché faltan en un futuro próximo y emitir parches previos automáticos para ingresar a la caché. Entonces la realidad Es que con las CPU modernas los modelos de rendimiento son tan complejos que resultan casi incomprensibles. Incluso los simuladores de hardware detallados nunca pueden igualar la lógica exacta de los chips, así que exacto la afinación es simplemente imposible ya

Todavía hay lugar para algunos códigos de mano. Las bibliotecas matemáticas (como decir 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 a mano 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 primera clase por mega-computer corp.

    
respondido por el Omega Centauri 28.11.2010 - 05:47
10

A veces paso (¿malgastando?) tiempo al elegir un buen nombre para una variable o un método para que no solo sea descriptivo, 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.

    
respondido por el user8685 28.11.2010 - 01:05
10

Complejidad del tiempo. Paso demasiado tiempo optimizando las cosas para el peor desempeño en una escala que es órdenes de magnitud más grande que cualquier otra cosa que sé que el programa encontrará de manera realista.

Soy demasiado obsesivo como para dejar de lado el 'pero podría crecer mucho', incluso cuando otras decisiones de diseño impiden que eso ocurra de manera realista.

Sin embargo, en mi defensa, si lo que no es realista se convierta en realidad ... la optimización realmente ya no es "micro". Tenga en cuenta que no dije imposible , sino irrealista .

Por supuesto, los requisitos tienen prioridad.

    
respondido por el Tim Post 28.11.2010 - 07:21
8

Creo que he perdido el tiempo de las semanas 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 una advertencia o una información? ¿Error o fatal? ¿Es realmente fatal si el proceso se reaparecerá en cinco minutos? ¿Es realmente una advertencia si todo sigue en estado predeterminado?

Un montón de ombligo mirando y discutiendo sobre la naturaleza de un error de 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í sucesivamente.

En un momento reemplazé todas las cadenas de concat con String.format para que el error de archivo anual no genere objetos adicionales en el montón. Eso fue un desperdicio.

    
respondido por el sal 28.11.2010 - 06:42
7

Supongo que me preocupan demasiado los LOC. No tanto los LOC en sí mismos, sino más bien el número de declaraciones y aún más número de declaraciones duplicadas. Soy alérgico al código duplicado. En general, me encanta la refactorización, pero supongo que alrededor del 50% de lo que hago no hace que el código sea mucho más agradable.

    
respondido por el back2dos 28.11.2010 - 01:12
5

Leer un archivo línea por línea en lugar de solo leer toda la línea en una cadena y procesar la cadena en una sola toma.

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í, es probable que esto no tenga sentido si el archivo tiene un tamaño de 3 GB pero la mayoría de los archivos no son tan grandes (al menos no con los que estoy trabajando ;-)).

    
respondido por el Oliver Weiler 28.11.2010 - 22:22
3

Cuando estaba escribiendo lenguaje ensamblador, tenía sentido repasar bytes y ciclos, pero eso fue hace mucho tiempo y los compiladores han avanzado mucho desde entonces. No trataría de optimizar manualmente uno ahora.

De manera similar, cuando cambié a escribir en C, fue bastante fácil hacer un mejor trabajo que los compiladores de C, pero cada año Borland o Microsoft o alguien lanzaría uno nuevo que mejoró el anterior en la sala . Comencé a prestar atención al código de ensamblaje real que estaba emitiendo el compilador y, si no estaba escribiendo algún código bonito y ajustado, desenrollando bucles, moviendo variables fuera de los bucles, etc.

Hoy en día estoy escribiendo en lenguajes mucho más altos como Perl, Python y Ruby. Utilizo algunos de los trucos del compilador por adelantado, como el desenrollado de bucles si tiene sentido, mover variables estáticas fuera de los bucles, etc., pero no me preocupo tanto porque las CPU son un poco más rápidas ahora. Si parece que una aplicación se está arrastrando inesperadamente, usaré un generador de perfiles y veré lo que puedo encontrar, y luego, si algo puede mejorarse, comenzaré a evaluar varias formas en las que puedo hacer algo más rápido, y luego veré escalas para arriba

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

    
respondido por el the Tin Man 28.11.2010 - 01:32
3

Una microoptimización: mejora el rendimiento de subprocesos simples de cosas que son paralelizables o que simplemente pueden mejorarse con nuevo hardware.

Si algo está lento en una computadora desde 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 en la optimización del tiempo del programador. Sin embargo, un gran enfoque de las optimizaciones debe ser encontrar una forma de utilizar los 8 núcleos que puede obtener hoy o los 64 que podrá obtener en un par de años, en lugar de agonizar sobre las minucias, como el costo adicional de la basura. colección.

    
respondido por el Kevin Cantu 28.11.2010 - 03:14
2

La microoptimización en términos de rendimiento en tiempo de ejecución no es un problema cerrado aún 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 a una función adicional es insignificante.

Aparte de eso, también veo a los programadores micro-optimizar por simplicidad (incluyéndome a mí). Todavía tengo que trabajar en algún lugar donde no tuve que explicar la diferencia entre simplicidad y simplismo.

    
respondido por el Jason Baker 28.11.2010 - 03:35
2

Estoy a favor del principio de no-optimizar-a menos que sea realmente necesario. Y estoy a favor del principio del perfil primero. Y, en principio, solo optimizaré algo que hará una diferencia necesaria.

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

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

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

Oh - y BTW. Nunca he usado un perfilador para guiar una optimización. No tengo acceso a uno comercial, y nunca he desarrollado 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?" por lo que nunca puedo aplicarlos correctamente a mí mismo.

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

EDIT

Debería agregar: uno de mis principales problemas estúpidos son los gastos generales de llamadas. No en todas partes, por supuesto, pero en esos casos de I-think-it-be-be-be-a-lot-in-inner-loop (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 ser incluso más lento, ya que probablemente no sea un estilo de codificación que los optimizadores estén diseñados para manejar bien, pero es más inteligente ;-)

    
respondido por el Steve314 28.11.2010 - 11:46
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 hacen que la microoptimización sea generalmente una pérdida total de tiempo. Las excepciones tienden a ser cuando tienes que obtener el máximo rendimiento de algún código computacional intensivo ... o estás escribiendo para un sistema integrado con recursos extremadamente limitados.

  

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

Twitter y Facebook vienen a la mente :-)

    
respondido por el Stephen C 28.11.2010 - 03:01

Lea otras preguntas en las etiquetas