En mi diseño de clase, uso clases abstractas y funciones virtuales ampliamente. Tenía la sensación de que las funciones virtuales afectan el rendimiento. ¿Es esto cierto? Pero creo que esta diferencia de rendimiento no es notable y parece que estoy haciendo una optimización prematura. ¿Correcto?
c++
performance
optimization
virtual-functions
Navaneeth KN
fuente
fuente
Respuestas:
Una buena regla general es:
El uso de funciones virtuales tendrá un efecto muy leve en el rendimiento, pero es poco probable que afecte el rendimiento general de su aplicación. Los mejores lugares para buscar mejoras de rendimiento son los algoritmos y las E / S.
Un excelente artículo que habla sobre funciones virtuales (y más) son los punteros de funciones de miembros y los delegados de C ++ más rápidos posibles .
fuente
Su pregunta me hizo sentir curiosidad, así que seguí adelante y ejecuté algunos tiempos en la CPU PowerPC en orden de 3 GHz con la que trabajamos. La prueba que ejecuté fue hacer una clase de vector 4d simple con funciones get / set
Luego configuré tres matrices que contenían 1024 de estos vectores (lo suficientemente pequeñas como para caber en L1) y ejecuté un ciclo que las agregó entre sí (Ax = Bx + Cx) 1000 veces. Me encontré con esto con las funciones definidas como
inline
,virtual
y llamadas a funciones regulares. Aquí están los resultados:Entonces, en este caso (donde todo cabe en la memoria caché), las llamadas a funciones virtuales fueron aproximadamente 20 veces más lentas que las llamadas en línea. Pero, ¿qué significa esto realmente? Cada viaje a través del bucle provocó exactamente
3 * 4 * 1024 = 12,288
llamadas a funciones (1024 vectores por cuatro componentes por tres llamadas por adición), por lo que estos tiempos representan1000 * 12,288 = 12,288,000
llamadas a funciones. El bucle virtual tardó 92 ms más que el bucle directo, por lo que la sobrecarga adicional por llamada fue de 7 nanosegundos por función.De esto concluyo: sí , las funciones virtuales son mucho más lentas que las directas, y no , a menos que esté planeando llamarlas diez millones de veces por segundo, no importa.
Ver también: comparación del conjunto generado.
fuente
Cuando Objective-C (donde todos los métodos son virtuales) es el idioma principal para el iPhone y Java es el idioma principal para Android, creo que es bastante seguro usar funciones virtuales C ++ en nuestras torres de doble núcleo de 3 GHz.
fuente
En aplicaciones críticas de rendimiento (como los videojuegos), una llamada a la función virtual puede ser demasiado lenta. Con el hardware moderno, la mayor preocupación de rendimiento es la pérdida de caché. Si los datos no están en el caché, pueden pasar cientos de ciclos antes de que estén disponibles.
Una llamada de función normal puede generar una falta de caché de instrucciones cuando la CPU obtiene la primera instrucción de la nueva función y no está en la caché.
Una llamada de función virtual primero necesita cargar el puntero vtable desde el objeto. Esto puede resultar en una pérdida de caché de datos. Luego carga el puntero de la función de la tabla vtable que puede resultar en otra pérdida de caché de datos. Luego llama a la función que puede resultar en un error de caché de instrucciones como una función no virtual.
En muchos casos, dos fallas de caché adicionales no son una preocupación, pero en un ciclo cerrado en el código crítico de rendimiento puede reducir drásticamente el rendimiento.
fuente
De la página 44 del manual "Optimización del software en C ++" de Agner Fog :
fuente
switch
. Concase
valores totalmente arbitrarios , claro. Pero si todos loscase
s son consecutivos, un compilador podría optimizar esto en una tabla de salto (ah, eso me recuerda a los viejos días de Z80), que debería ser (por falta de un término mejor) tiempo constante. No es que recomiendo tratar de reemplazar vfuncs conswitch
, lo cual es ridículo. ;)absolutamente. Era un problema cuando las computadoras funcionaban a 100Mhz, ya que cada llamada al método requería una búsqueda en la tabla antes de que se llamara. Pero hoy ... ¿en una CPU de 3Ghz que tiene caché de primer nivel con más memoria que mi primera computadora? De ningún modo. Asignar memoria de la RAM principal le costará más tiempo que si todas sus funciones fueran virtuales.
Es como en los viejos tiempos, donde la gente decía que la programación estructurada era lenta porque todo el código se dividía en funciones, ¡cada función requería asignaciones de pila y una llamada a la función!
La única vez que pensaría en molestarme en considerar el impacto en el rendimiento de una función virtual es si se usa mucho y se instancia en un código con plantilla que terminó en todo. ¡Incluso entonces, no gastaría demasiado esfuerzo en ello!
PD: piense en otros lenguajes 'fáciles de usar': todos sus métodos son virtuales y no se arrastran hoy en día.
fuente
Hay otro criterio de rendimiento además del tiempo de ejecución. Un Vtable también ocupa espacio en la memoria y, en algunos casos, se puede evitar: ATL utiliza " enlace dinámico simulado " en tiempo de compilación con plantillaspara obtener el efecto del "polimorfismo estático", que es difícil de explicar; básicamente pasa la clase derivada como parámetro a una plantilla de clase base, por lo que en el momento de la compilación la clase base "sabe" cuál es su clase derivada en cada instancia. No le permitirá almacenar múltiples clases derivadas diferentes en una colección de tipos base (es decir, polimorfismo en tiempo de ejecución), pero desde un sentido estático, si desea hacer una clase Y que sea igual a una clase de plantilla X preexistente que tiene el ganchos para este tipo de anulación, solo necesita anular los métodos que le interesan, y luego obtiene los métodos básicos de la clase X sin tener que tener una vtable.
En clases con grandes huellas de memoria, el costo de un solo puntero de vtable no es mucho, pero algunas de las clases de ATL en COM son muy pequeñas, y vale la pena el ahorro de vtable si el caso de polimorfismo en tiempo de ejecución nunca va a ocurrir.
Ver también esta otra pregunta SO .
Por cierto, aquí hay una publicación que encontré que habla sobre los aspectos de rendimiento del tiempo de CPU.
fuente
Sí, tienes razón y si tienes curiosidad sobre el costo de la función virtual, puedes encontrar esta publicación interesante.
fuente
La única forma en que puedo ver que una función virtual se convertirá en un problema de rendimiento es si se invocan muchas funciones virtuales dentro de un ciclo cerrado, y si y solo si causan una falla de página u otra operación de memoria "pesada".
Aunque, como han dicho otras personas, nunca será un problema para ti en la vida real. Y si cree que es así, ejecute un generador de perfiles, haga algunas pruebas y verifique si esto realmente es un problema antes de intentar "no diseñar" su código para obtener un beneficio de rendimiento.
fuente
Cuando el método de clase no es virtual, el compilador generalmente lo hace en línea. Por el contrario, cuando usa el puntero a alguna clase con función virtual, la dirección real solo se conocerá en tiempo de ejecución.
Esto está bien ilustrado por prueba, diferencia de tiempo ~ 700% (!):
El impacto de la llamada a función virtual depende en gran medida de la situación. Si hay pocas llamadas y una cantidad significativa de trabajo dentro de la función, podría ser insignificante.
O, cuando se trata de una llamada virtual que se usa repetidamente muchas veces, mientras se realiza una operación simple, podría ser realmente grande.
fuente
++ia
. ¿Y qué?He ido y venido en esto al menos 20 veces en mi proyecto particular. Aunque puede haber algunas grandes ganancias en términos de reutilización de código, claridad, facilidad de mantenimiento y legibilidad, por otro lado, los éxitos en el rendimiento aún lo hacen existir con funciones virtuales.
¿El rendimiento será notable en una computadora portátil / computadora de escritorio / tableta moderna ... probablemente no! Sin embargo, en ciertos casos con sistemas integrados, el impacto en el rendimiento puede ser el factor determinante de la ineficiencia de su código, especialmente si la función virtual se llama una y otra vez en un bucle.
Aquí hay un documento anticuado que analiza las mejores prácticas para C / C ++ en el contexto de los sistemas integrados: http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_Boston_01_304_paper.pdf
Para concluir: depende del programador comprender las ventajas y desventajas de utilizar una determinada construcción sobre otra. A menos que esté impulsado por el rendimiento súper, probablemente no le importe el impacto en el rendimiento y debería usar todas las cosas ordenadas de OO en C ++ para ayudar a que su código sea lo más utilizable posible.
fuente
En mi experiencia, lo más relevante es la capacidad de alinear una función. Si tiene necesidades de rendimiento / optimización que dictan que una función debe estar en línea, entonces no puede hacer que la función sea virtual porque eso lo evitaría. De lo contrario, probablemente no notarás la diferencia.
fuente
Una cosa a tener en cuenta es que esto:
puede ser más rápido que esto:
Esto se debe a que el primer método solo llama a una función, mientras que el segundo puede llamar a muchas funciones diferentes. Esto se aplica a cualquier función virtual en cualquier idioma.
Digo "puede" porque esto depende del compilador, el caché, etc.
fuente
La penalización de rendimiento del uso de funciones virtuales nunca puede superar las ventajas que obtienes a nivel de diseño. Supuestamente, una llamada a una función virtual sería un 25% menos eficiente que una llamada directa a una función estática. Esto se debe a que existe un nivel de indirección a través de VMT. Sin embargo, el tiempo necesario para realizar la llamada normalmente es muy pequeño en comparación con el tiempo empleado en la ejecución real de su función, por lo que el costo total de rendimiento será insignificante, especialmente con el rendimiento actual del hardware. Además, el compilador a veces puede optimizar y ver que no se necesita una llamada virtual y compilarlo en una llamada estática. Así que no se preocupe, use funciones virtuales y clases abstractas tanto como lo necesite.
fuente
The performance penalty of using virtual functions can sometimes be so insignificant that it is completely outweighed by the advantages you get at the design level.
La diferencia clave dicesometimes
, nonever
.Siempre me cuestioné esto, especialmente porque, hace unos años, también hice una prueba de este tipo comparando los tiempos de una llamada de método de miembro estándar con una virtual y estaba realmente enojado por los resultados en ese momento, teniendo llamadas virtuales vacías. 8 veces más lento que los no virtuales.
Hoy tuve que decidir si usar o no una función virtual para asignar más memoria en mi clase de búfer, en una aplicación muy crítica para el rendimiento, así que busqué en Google (y te encontré), y al final, volví a hacer la prueba.
Y realmente me sorprendió que, de hecho, realmente ya no importa. Si bien tiene sentido tener líneas en línea más rápidas que las no virtuales, y que sean más rápidas que las virtuales, a menudo se trata de la carga de la computadora en general, ya sea que su caché tenga los datos necesarios o no, y si bien puede optimizar a nivel de caché, creo que esto debería ser realizado por los desarrolladores del compilador más que por los desarrolladores de aplicaciones.
fuente