Todos dicen que debería hacer que mi código sea modular, pero ¿no es menos eficiente si uso más llamadas a métodos en lugar de menos métodos, pero más grandes? ¿Cuál es la diferencia en Java, C o C ++ para el caso?
Entiendo que es más fácil editar, leer y comprender, especialmente en un grupo. Entonces, ¿la pérdida de tiempo de cálculo es insignificante en comparación con los beneficios de ordenamiento del código?
java
c++
c
efficiency
fatsokol
fuente
fuente
Respuestas:
Sí, es irrelevante.
Las computadoras son incansables, motores de ejecución casi perfectos que trabajan a velocidades totalmente incomparables a los cerebros. Si bien hay una cantidad de tiempo medible que una llamada de función agrega al tiempo de ejecución de un programa, esto no es nada en comparación con el tiempo adicional que necesita el cerebro de la siguiente persona involucrada con el código cuando tienen que desenredar la rutina ilegible incluso comenzar a entender cómo trabajar con él. Puede probar el cálculo como una broma: suponga que su código debe mantenerse solo una vez , y solo agrega media hora al tiempo necesario para que alguien acepte el código. Tome la velocidad de reloj de su procesador y calcule: ¿cuántas veces tendría que ejecutarse el código para soñar con compensar eso?
En resumen, sentir lástima por la CPU es completamente, totalmente equivocado el 99.99% del tiempo. Para los raros casos restantes, use perfiladores. No , no asumir que se puede detectar esos casos - no se puede.
fuente
Depende.
En el mundo glacialmente lento que es la programación web, donde todo sucede a velocidades humanas, la programación de método pesado, donde el costo de la llamada al método es comparable o excede el costo del procesamiento realizado por el método, probablemente no importa .
En el mundo de la programación de sistemas embebidos y los manejadores de interrupciones para interrupciones de alta velocidad, ciertamente importa. En ese entorno, los modelos habituales de "acceso a la memoria es barato" y "el procesador es infinitamente rápido" se descomponen. He visto lo que sucede cuando un programador orientado a objetos de mainframe escribe su primer controlador de interrupciones de alta velocidad. No fue lindo.
Hace varios años, estaba coloreando blobs de conectividad de 8 vías no recursivos en imágenes FLIR en tiempo real, en lo que en ese momento era un procesador decente. El primer intento utilizó una llamada de subrutina, y la sobrecarga de la llamada de subrutina se comió el procesador vivo. (4 llamadas POR PÍXEL x 64K píxeles por cuadro x 30 cuadros por segundo = lo resuelves). El segundo intento cambió la subrutina a una macro C, sin pérdida de legibilidad, y todo fue rosas.
Tienes que mirar DURO a lo que estás haciendo y al entorno en el que lo harás.
fuente
En primer lugar: los programas en un idioma superior son para ser leídos por humanos y no por máquinas.
Así que escribir los programas para que usted los entiende. No piense en el rendimiento (si tiene problemas graves de rendimiento, perfile su aplicación y mejore el rendimiento donde sea necesario).
Incluso si es cierto que llamar a un método o función requiere cierta sobrecarga, esto no importa. Hoy los compiladores deberían poder compilar su código en un lenguaje de máquina eficiente para que el código generado sea eficiente para la arquitectura de destino. Use los interruptores de optimización de su compilador para obtener el código eficiente.
fuente
Por lo general, cuando de lo contrario tendría una función grande y la dividiera en muchas más pequeñas, estas se alinearán porque la única desventaja de la inserción (repetir las mismas instrucciones demasiado) no es relevante en este caso. Eso significa que su código actuará como si hubiera escrito una función grande.
Si no están alineados por algún motivo y esto se convierte en un problema de rendimiento, entonces debe considerar la inserción manual. No todas las aplicaciones son formularios CRUD en red con enormes latencias intrínsecas.
fuente
Probablemente no hay costo de cálculo. Por lo general, los compiladores / JIT de los últimos 10-20 años más o menos se ocupan de la función de alineación perfectamente bien. Para C / C ++ generalmente se limita a funciones 'inlinable' (es decir, la definición de función está disponible para el compilador durante la compilación, es decir, está en el encabezado del mismo archivo), pero las técnicas actuales de LTO lo superan.
Si debe dedicar tiempo a la optimización depende del área en la que esté trabajando. Si maneja una aplicación 'normal' que pasó la mayor parte del tiempo esperando la entrada, probablemente no debería preocuparse por las optimizaciones a menos que la aplicación se sienta 'lenta'.
Incluso en tales casos, debe concentrarse en muchas cosas antes de hacer la microoptimización:
O(n)
aO(log n)
podría tener un impacto mucho mayor que cualquier cosa que pueda lograr con la microoptimización.List
cuando lo necesitaHashSet
para tenerO(n)
búsquedas cuando podría haberlo hechoO(1)
.Incluso si decide que necesita realizar una microoptimización (lo que prácticamente significa que su software se usa en HPC, incrustado o simplemente utilizado por un gran número de personas; de lo contrario, el costo adicional de mantenimiento supera los costos de tiempo de la computadora) que necesita para identificar los puntos de acceso (núcleos) que desea acelerar. Pero entonces probablemente deberías:
Como comentario final. Por lo general, el único problema que tiene con las llamadas a métodos son los saltos indirectos (métodos virtuales) que no fueron predichos por el predictor de rama (desafortunadamente, el salto indirecto es el caso difícil). Sin embargo:
fuente
Mi respuesta probablemente no se ampliará demasiado en las respuestas existentes, pero siento que mis dos centavos pueden ser útiles.
Antes que nada; sí, por modularidad, generalmente renuncia a cierto nivel de tiempo de ejecución. Escribir todo en el código de ensamblaje te dará la mejor velocidad. Dicho eso ...
¿Conoces YouTube? ¿Es probable que sea el sitio de mayor ancho de banda existente o el segundo después de Netflix? Escriben una gran parte de su código en Python, que es un lenguaje altamente modular que no está construido para un rendimiento de primer nivel.
El problema es que cuando algo sale mal y los usuarios se quejan de que los videos se cargan lentamente, no hay muchos escenarios en los que esa lentitud se atribuya a la lenta velocidad de ejecución de Python. Sin embargo, la rápida compilación de Python y su capacidad modular para probar cosas nuevas sin verificación de tipo probablemente permitirán a los ingenieros depurar lo que está sucediendo bastante rápido ("Wow. Nuestro nuevo interno escribió un bucle que hace una nueva subconsulta SQL para CADA resultado ") o (" Oh, Firefox ha dejado de usar ese antiguo formato de encabezado de almacenamiento en caché; e hicieron una biblioteca de Python para configurar el nuevo fácilmente ")
En ese sentido, incluso en términos de tiempo de ejecución, un lenguaje modular puede considerarse más rápido porque una vez que encuentre cuáles son sus cuellos de botella, probablemente será más fácil reorganizar su código para que funcione de la mejor manera. Muchos ingenieros le dirán que los grandes golpes de rendimiento no fueron donde pensaban que estarían (y, de hecho, las cosas que optimizaron apenas fueron necesarias; ¡o ni siquiera funcionaron de la manera que esperaban!)
fuente
Si y no. Como otros han señalado el programa de legibilidad primero, luego de eficiencia. Sin embargo, hay prácticas estándar que son legibles y eficientes. La mayoría del código se ejecuta con poca frecuencia, y de todos modos no obtendrá muchas ventajas al optimizarlo.
Java puede alinear llamadas a funciones más pequeñas, por lo que hay pocas razones para evitar escribir las funciones. Los optimizadores tienden a funcionar mejor con un código más simple y fácil de leer. Hay estudios que muestran atajos que, en teoría, deberían ejecutarse más rápido, en realidad tomar más tiempo. Es probable que el compilador JIT funcione mejor, el código es más pequeño y las piezas ejecutadas con frecuencia se pueden identificar y optimizar. No lo he probado, pero esperaría que una función grande que se llama relativamente raramente no se compile.
Es probable que esto no se aplique a Java, pero un estudio encontró que las funciones más grandes en realidad se ejecutaron más lentamente debido a que requieren un modelo de referencia de memoria diferente. Esto fue específico de hardware y optimizador. Para módulos más pequeños se utilizaron instrucciones que funcionaban dentro de una página de memoria. Estos fueron más rápidos y pequeños que las instrucciones requeridas cuando la función no se ajustaba a una página.
Hay casos en los que vale la pena optimizar el código, pero en general es necesario perfilar el código para determinar dónde está. Creo que a menudo no es el código que esperaba.
fuente