Mi pregunta está relacionada con las características de rendimiento de los métodos estáticos frente a los métodos de instancia y su escalabilidad. Suponga para este escenario que todas las definiciones de clase están en un solo ensamblaje y que se requieren múltiples tipos de punteros discretos.
Considerar:
public sealed class InstanceClass
{
public int DoOperation1(string input)
{
// Some operation.
}
public int DoOperation2(string input)
{
// Some operation.
}
// … more instance methods.
}
public static class StaticClass
{
public static int DoOperation1(string input)
{
// Some operation.
}
public static int DoOperation2(string input)
{
// Some operation.
}
// … more static methods.
}
Las clases anteriores representan un patrón de estilo auxiliar.
En una clase de instancia, la resolución del método de instancia toma un momento para oponerse a StaticClass.
Mis preguntas son:
Cuando mantener el estado no es una preocupación (no se requieren campos o propiedades), ¿es siempre mejor usar una clase estática?
Donde hay un número considerable de estas definiciones de clases estáticas (digamos 100, por ejemplo, con varios métodos estáticos cada una), ¿afectará esto el rendimiento de ejecución o el consumo de memoria de manera negativa en comparación con el mismo número de definiciones de clases de instancia?
Cuando se llama a otro método dentro de la misma clase de instancia, ¿sigue ocurriendo la resolución de la instancia? Por ejemplo, usando la palabra clave [this] como
this.DoOperation2("abc")
desde dentroDoOperation1
de la misma instancia.
fuente
this
apunta a algo cuando una clase llama a un método de instancia sobre sí misma?"Respuestas:
En teoría, un método estático debería funcionar ligeramente mejor que un método de instancia, en igualdad de condiciones, debido al
this
parámetro oculto adicional .En la práctica, esto hace tan poca diferencia que quedará oculto en el ruido de varias decisiones del compilador. (Por lo tanto, dos personas podrían "probar" una mejor que la otra con resultados en desacuerdo). Sobre todo porque
this
normalmente se pasa en un registro y, para empezar, a menudo se encuentra en ese registro.Este último punto significa que, en teoría, deberíamos esperar que un método estático que toma un objeto como parámetro y hace algo con él sea un poco menos bueno que el equivalente como instancia en ese mismo objeto. Sin embargo, una vez más, la diferencia es tan pequeña que si intenta medirla probablemente terminará midiendo alguna otra decisión del compilador. (Especialmente porque la probabilidad de que esa referencia esté en un registro todo el tiempo también es bastante alta).
Las diferencias reales de rendimiento se reducirán a si tienes objetos en la memoria de forma artificial para hacer algo que naturalmente debería ser estático, o estás enredando cadenas de paso de objetos de formas complicadas para hacer lo que naturalmente debería ser una instancia.
Por lo tanto, para el número 1. Cuando mantener el estado no es una preocupación, siempre es mejor ser estático, porque para eso es estático . No es un problema de rendimiento, aunque hay una regla general de jugar bien con las optimizaciones del compilador: es más probable que alguien se haya esforzado por optimizar los casos que surgen con el uso normal que los que surgen con un uso extraño.
Número 2. No importa. Hay una cierta cantidad de costo por clase para cada miembro en términos de la cantidad de metadatos que hay, la cantidad de código que hay en el archivo DLL o EXE real y la cantidad de código jitted que habrá. Esto es lo mismo ya sea de instancia o estático.
Con el ítem 3,
this
es comothis
hace. Sin embargo nota:El
this
parámetro se pasa en un registro particular. Al llamar a un método de instancia dentro de la misma clase, es probable que ya esté en ese registro (a menos que esté escondido y el registro se haya usado por alguna razón) y, por lo tanto, no se requiere ninguna acción para establecer el valorthis
que debe establecerse. . Esto se aplica hasta cierto punto a, por ejemplo, que los dos primeros parámetros del método son los dos primeros parámetros de una llamada que realiza.Como quedará claro que
this
no es nulo, esto se puede utilizar para optimizar las llamadas en algunos casos.Como quedará claro que
this
no es nulo, esto puede hacer que las llamadas al método en línea sean más eficientes nuevamente, ya que el código producido para falsificar la llamada al método puede omitir algunas comprobaciones nulas que podría necesitar de todos modos.Dicho esto, los cheques nulos son baratos.
Vale la pena señalar que los métodos estáticos genéricos que actúan sobre un objeto, en lugar de los métodos de instancia, pueden reducir algunos de los costos discutidos en http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- the-associated-overheads / en el caso de que esa estática dada no se llame para un tipo determinado. Como él dice: "Dejando de lado, resulta que los métodos de extensión son una excelente manera de hacer que las abstracciones genéricas sean más rentables".
Sin embargo, tenga en cuenta que esto se relaciona solo con la creación de instancias de otros tipos utilizados por el método, que de otra manera no existen. Como tal, realmente no se aplica a muchos casos (algún otro método de instancia usó ese tipo, algún otro código en otro lugar usó ese tipo).
Resumen:
Editar: Una nota sobre cuán baratos son los controles nulos (que reclamé anteriormente). La mayoría de las comprobaciones de nulos en .NET no comprueban nulos en absoluto, sino que continúan con lo que iban a hacer con la suposición de que funcionará, y si ocurre una excepción de acceso, se convierte en un archivo
NullReferenceException
. Como tal, principalmente cuando conceptualmente el código C # implica una verificación nula porque está accediendo a un miembro de instancia, el costo si tiene éxito es en realidad cero. Una excepción serían algunas llamadas en línea (porque quieren comportarse como si llamaran a un miembro de instancia) y simplemente presionan un campo para activar el mismo comportamiento, por lo que también son muy baratas y, de todos modos, a menudo se pueden omitir. (por ejemplo, si el primer paso del método implicaba acceder a un campo tal como estaba).fuente
this
través de un parámetro explícito. Un mayor impacto aquí sería qué tan cerca están los datos de los datos relacionados (los campos de tipo de valor o los valores de matriz están más cerca que los datos de los campos de tipo de referencia) y los patrones de acceso.obj.DoSomehting(2)
que sea un poco más barato que,DoSomething(obj, 2)
pero como también dije, la diferencia es tan pequeña y tan dependiente de cosas pequeñas que podrían terminar siendo diferentes en la compilación final que realmente no vale la pena preocuparse en absoluto. Si está haciendo algo tan caro (en relación con el tipo de diferencias en juego aquí) como serializar algo en una cadena, entonces es especialmente inútil.ctor
todavía requiere la inicialización de todos los campos. Una vez que ya tenga una instancia, esta respuesta se aplica ("en igualdad de condiciones"). Por supuesto, un costo caro tambiéncctor
puede hacer que los métodos estáticos sean lentos, pero eso es solo en la primera llamada y se aplica igualmente a los métodos de instancia. Consulte también docs.microsoft.com/en-us/previous-versions/dotnet/articles/…Yo diría que sí. Al declarar algo
static
, declaras una intención de ejecución sin estado (no es obligatorio, pero una intención de algo que uno esperaría)No lo crea, a menos que esté seguro de que las clases estáticas realmente no tienen stet, porque si no, es fácil estropear las asignaciones de memoria y tener pérdidas de memoria.
No estoy seguro sobre este punto (este es un detalle puramente de implementación de CLR), pero piense que sí.
fuente
Los métodos estáticos son más rápidos pero menos OOP, si va a utilizar patrones de diseño, es probable que el método estático sea un código incorrecto, para escribir la lógica empresarial mejor sin estáticas, funciones comunes como lectura de archivos, WebRequest, etc. responder
fuente