Normalmente odio la palabra, "optimización prematura", pero esto apesta. Vale la pena señalar que Knuth utilizó esta famosa cita en el contexto de presionar para usar goto
enunciados con el fin de acelerar el código en las áreas críticas . Esa es la clave: ruta crítica .
Estaba sugiriendo usar goto
para acelerar el código, pero advirtió contra aquellos programadores que querrían hacer este tipo de cosas basadas en corazonadas y supersticiones para códigos que ni siquiera son críticos.
Para favorecer las declaraciones switch
tanto como sea posible uniformemente a lo largo de una base de código (ya sea que se maneje o no una carga pesada) es el ejemplo clásico de lo que Knuth llama "penny-wise y pound- "Programador tonto que pasa todo el día luchando para mantener su código" optimizado "que se convirtió en una pesadilla de depuración como resultado de intentar ahorrar centavos de más. Dicho código rara vez se puede mantener y mucho menos, incluso, es eficiente en primer lugar.
¿Tiene razón?
Él es correcto desde la perspectiva de la eficiencia muy básica. Ningún compilador, que yo sepa, puede optimizar el código polimórfico que involucra objetos y el envío dinámico mejor que una instrucción switch. Nunca terminará con una LUT o una tabla de salto a código en línea desde el código polimórfico, ya que dicho código tiende a servir como una barrera optimizadora para el compilador (no sabrá a qué función llamar hasta el momento en que el envío dinámico ocurre).
Es más útil no pensar en este costo en términos de tablas de salto, sino más en términos de la barrera de optimización. Para el polimorfismo, llamar a Base.method()
no le permite al compilador saber qué función terminará siendo llamada si method
es virtual, no está sellada, y puede ser anulada. Dado que no sabe qué función se llamará por adelantado, no puede optimizar la llamada de función y utilizar más información para tomar decisiones de optimización, ya que no sabe realmente a qué función se llamará en La hora en que se está compilando el código.
Los optimizadores están en su mejor momento cuando pueden mirar en una llamada de función y hacer optimizaciones que aplanan completamente a la persona que llama y a la persona que llama, o al menos optimizan a la persona que llama para que trabaje de manera más eficiente con la persona que llama. No pueden hacerlo si no saben a qué función se va a llamar de antemano.
¿Está simplemente hablando por el culo?
El uso de este costo, que a menudo equivale a centavos, para justificar que se convierta en un estándar de codificación aplicado de manera uniforme generalmente es muy tonto, especialmente para lugares que tienen una necesidad de extensibilidad. Eso es lo principal que debe tener en cuenta con los optimizadores prematuros genuinos: quieren convertir los problemas menores de rendimiento en estándares de codificación aplicados de manera uniforme en toda la base de código sin tener en cuenta el mantenimiento en absoluto.
Sin embargo, me ofende un poco la cita del "viejo hacker C" que se usa en la respuesta aceptada, ya que soy uno de ellos. No todos los que han estado codificando durante décadas a partir de un hardware muy limitado se han convertido en un optimizador prematuro. Sin embargo, he encontrado y trabajado con ellos también. Pero esos tipos nunca miden cosas como la falta de predicción de la rama o las fallas de caché, creen que lo saben mejor y basan sus nociones de ineficiencia en una base de código de producción compleja basada en supersticiones que hoy no son ciertas y que a veces nunca son verdaderas. Las personas que realmente han trabajado en campos críticos para el rendimiento a menudo entienden que la optimización efectiva es una priorización efectiva, y tratar de generalizar un estándar de codificación degradante de mantenimiento para ahorrar centavos es una priorización muy ineficaz.
Los centavos son importantes cuando tienes una función barata que no hace tanto trabajo que se llama mil millones de veces en un bucle muy ajustado y crítico para el rendimiento. En ese caso, terminamos ahorrando 10 millones de dólares. No vale la pena afeitar centavos cuando tiene una función llamada dos veces por la cual el cuerpo solo cuesta miles de dólares. No es aconsejable pasar su tiempo regateando centavos durante la compra de un automóvil. Vale la pena regatear sobre centavos si está comprando un millón de latas de refresco de un fabricante. La clave para una optimización efectiva es comprender estos costos en su contexto adecuado. Alguien que intenta ahorrar centavos en cada compra y sugiere que todos los demás intentan regatear centavos sin importar lo que estén comprando, no es un optimizador experto.