2010-01-26 18 views
38

En términos de memoria y tiempo, ¿es mejor hacer un método estático?¿Los métodos estáticos son más eficientes?

+1

Para responder a su pregunta: sí, pero nunca debe tener eso en cuenta. Ver la respuesta de LBushkin. –

+0

Se reformuló por completo la pregunta. Parecía que te referías al proceso real de hacer un método estático.;) Las herramientas de refactorización hacen que este proceso sea más rápido. –

Respuesta

75

Normalmente sí, no es necesario pasar la referencia "this". Esa referencia se pasa en el registro ECX por lo que no se requiere espacio de pila adicional. El registro ya está configurado si realiza la llamada desde un método de instancia de la misma clase, no habrá ningún ahorro. Pero puede ayudar a aliviar la presión sobre un núcleo de CPU x86 cuando el método está en otra clase, x86 no tiene muchos registros. Ver una mejora de perf mensurable sería extremadamente raro.

Personalmente marco los métodos de una clase que no usan miembros de instancia como estáticos. Valoro el contrato inherente proporcionado por la palabra clave estática: "este método no muta el estado del objeto".

+15

+1 para el último párrafo: esto es realmente lo que importa aquí y hace 'static 'invaluable. –

+0

moderno x 86 cpus use aliasing de registro. –

+0

@Konrad, gracias por el voto popular. Vemos igual. –

7

Si va a pasar la instancia de todos modos (SomeStaticMethod(obj, "abc", 123);), entonces realmente no. Solo puede usar de manera útil un método estático en un escenario sin polimorfismo, y en tales casos es muy probable que simples cosas como propiedades se hayan insertado de todos modos.

utilizar objetos "naturalmente" (obj.SomeMethod("abc",123);) - mantener el código simple y perfil para encontrar problemas de rendimiento - es muy poco probable que sea en la diferencia entre la instancia y estática a menos que esté ejecutando algún muy bucles apretados. Hay son algunos escenarios donde podría importar, pero son bastante especializados.

49

Debe establecer un método estático si no requiere información de estado de la clase de la que forma parte.

Si no se preocupan por el polimorfismo, puede escribir cualquier método como cualquiera de los casos o estática con sólo decidir si tomar los miembros de instancia de clase y los pasa al método como argumentos. Lo que debe considerar, es si la sintaxis es natural, si el código es fácil de entender y si es significativo, y así sucesivamente.

Probablemente no deba preocuparse por la optimización en este nivel, porque la sobrecarga de rendimiento de una instancia frente a un método estático es insignificante. Sí, hay un espacio utilizado en la tabla de envío para el tipo (si el método es virtual), pero es una sobrecarga pequeña y constante. Sí, también hay una pequeña sobrecarga al invocar un método de instancia versus un método estático, pero de nuevo es muy pequeño.

Esto parece un nivel de micro-optimización, que a menos que tenga evidencia mensurable y tangible para creer que en realidad está afectando el rendimiento del programa, debe evitarlo. De hecho, si hace las cosas mal, el costo de pasar parámetros adicionales (copiarlos en la pila, etc.) en lugar de acceder a ellos a través de la referencia this oculta de su tipo, puede dar como resultado peor rendimiento.

Es mejor analizar la semántica del método y tomar la decisión estática/de instancia sobre esa base.

+2

Entiendo que el código IL que genera Microsoft C# usa el despacho virtual (callvirt) para todos los métodos de instancia, ya sea virtual o no, incluso para clases selladas. Esto es para usar la verificación nula incorporada de callvirt. De lo contrario, una verificación nula debería codificarse, ya que CLR no tiene problemas para invocar un método de instancia en una instancia nula. –

+0

Sí, pero teóricamente, el jitter puede alinear métodos no virtuales en ciertos casos. También puede hacer un análisis estático para reemplazar 'callvirt' en casos como clases selladas, y así sucesivamente. No estoy seguro de hasta qué punto hace esto, pero es posible. – LBushkin

+7

Para citar al gran Jeff Atwood: puedes escribir Fortran en cualquier idioma. – Nick

1

La diferencia es insignificante en la mayoría de los casos, pero la estática es más eficiente.

Los siguientes pasos se evitan en una llamada de método estático:

  1. la comprobación de que la referencia de objeto (esto) no es nulo.
  2. Encontrar el método correcto en la tabla de despacho virtual.
  3. Colocando la referencia del objeto en la pila.
0

Me parece que muchos métodos de utilidad que escribo dentro de una clase determinada solo necesitan unos pocos miembros de datos en la clase, o ninguno en absoluto. En estos casos, tiendo a escribir esos métodos como métodos estáticos (independientes), pasando directamente los pocos elementos de datos que necesitan.

Si son particularmente generales y lo suficientemente útiles para otras clases, puedo hacerlas públicas también.

3

Hay muchas preguntas de este tipo. ¿Son los métodos estáticos más rápidos/más lentos? ¿Las funciones virtuales son más rápidas/lentas? ¿Soy ++ más rápido/lento que ++ i? ¿Es para (;;) más rápido/más lento que mientras (verdadero)?

Vale la pena conseguir un software y tuning it. Eso le dará una buena idea de los tipos de cosas que realmente afectan el rendimiento del software, en la práctica.

Luego verá que la respuesta a preguntas como esa es (la mayoría de las veces) que es insignificante.

Si puedo generalizar, las cosas que hacen que el software sea lento, en mi experiencia, son el uso de líneas de código que parecen inocentes pero cuyo consumo de tiempo puede ser de órdenes de magnitud mayor de lo que podría imaginarse. Como parecen inocentes, no se pueden encontrar de manera confiable mirando el código. Ejemplos: asignación, inicialización y desasignación repetidas de grandes estructuras de datos para asignarlas. Internacionalizando cadenas que no necesitan ser. Programación de estilo de notificación que puede convertir una configuración simple de una propiedad en una cascada masiva de llamadas a métodos a lo largo de una gran estructura de datos. Operaciones simples O (n^2) que nunca habrían sido un problema excepto que n se ha hecho grande. Pensando que (a < b) toma aproximadamente el mismo período de tiempo si a y b son enteros o grandes clases. Esta "multiplicación del tiempo al parecer inocente" tiene un efecto de composición sobre múltiples capas de abstracción, por lo que el software grande tiende a estar plagado de él, en mi experiencia.

5

Hay poca o ninguna diferencia entre un método estático y un método de instancia no virtual. Este último solo tiene la referencia/referencia this como un argumento "oculto". En el código máquina generado, ambos tipos de llamadas se ven muy similares.

Un método debe ser estático si no depende de/modificar el objeto.

Los métodos virtuales (anulables) por otro lado requieren que la persona que llama busque la implementación exacta en el llamado vtable. Además de evitar que el compilador incorpore métodos muy pequeños (los accesores simples de propiedad se insertan muy a menudo) la búsqueda lleva un par de ciclos.

Aún así, los métodos virtuales son el tipo más rápido de despacho dinámico disponible en C#/en el CLR. Mucho más rápido que delegados y reflexión.

Cuestiones relacionadas