2008-10-14 12 views
27

Estoy trabajando en un proyecto en C#. El programador anterior no conocía la programación orientada a objetos, por lo que la mayor parte del código está en archivos enormes (estamos hablando de 4-5000 líneas) repartidos en decenas y a veces cientos de métodos, pero solo una clase. Refactorizar un proyecto de este tipo es una tarea enorme, por lo que he aprendido a vivir con esto por ahora.Rendimiento del uso de métodos estáticos frente a la creación de instancias de la clase que contiene los métodos

Cada vez que se utiliza un método en uno de los archivos de código, se crea una instancia de la clase y luego se invoca el método en la instancia del objeto.

Me pregunto si hay penalizaciones notables en el rendimiento al hacerlo de esta manera? ¿Debo hacer todos los métodos estáticos "por ahora" y, lo más importante, la aplicación se beneficiará de alguna manera?

+0

creo que esto se debe migrar a CS.SE –

Respuesta

24

De here, una llamada estática es de 4 a 5 veces más rápida que construir una instancia cada vez que llama a un método de instancia. Sin embargo, solo estamos hablando de decenas de nanosegundos por llamada, por lo que es poco probable que note algún beneficio a menos que tenga lazos estrechos que llamen a un método millones de veces, y podría obtener el mismo beneficio construyendo una sola instancia afuera ese bucle y reutilizarlo.

Ya que tendría que cambiar cada sitio de llamada para usar el nuevo método estático, probablemente sea mejor invertir su tiempo en la refactorización gradual.

+0

artículo impresionante. Empecé a hacer esto porque estaba interesado en lo que es más rápido. "While object.read" o For-Loop y IF. Y este artículo es simplemente lo perfecto después de mi investigación personal. Muy agradable. Ahora tengo un objeto muy grande al que se accede en muchos lugares y me pregunto si merece la pena pasar el método por el método al lugar que tiene que ir o simplemente hacer una clase de variables globales y acceder allí. Difícil de probar, ¿qué será más rápido ...? :( –

2

Me parece tonto crear un objeto SÓLO para que pueda llamar a un método que aparentemente no tiene efectos secundarios en el objeto (de su descripción lo asumo). Me parece que un mejor compromiso sería tener varios objetos globales y simplemente usarlos. De esta forma, puede colocar las variables que normalmente serían globales en las clases apropiadas para que tengan un alcance ligeramente menor.

Desde allí, puede mover lentamente el alcance de estos objetos para que sean más pequeños y más pequeños hasta que tenga un diseño OOP decente.

Por otra parte, el enfoque que I probablemente usaría es diferente;).

Personalmente, probablemente me centraría en las estructuras y las funciones que operan sobre ellas y trataré de convertirlas en clases con miembros poco a poco.

En cuanto al aspecto de rendimiento de la pregunta, los métodos estáticos deberían ser un poco más rápidos (pero no demasiado) ya que no implican construir, pasar y deconstruir un objeto.

3

Creo que ha respondido parcialmente a esta pregunta en la forma en que la hizo: ¿hay alguna penalizaciones de rendimiento notables en el código que tenga??

Si las penalizaciones no son perceptibles, no es necesario que haga absolutamente nada. (Aunque es evidente que la base de código se beneficiaría espectacularmente de un refactor gradual en un respetable modelo OO).

Supongo que lo que estoy diciendo es que un problema de rendimiento es solo un problema cuando se da cuenta de que es un problema.

7

Depende de qué más contiene ese objeto; si el "objeto" es simplemente un conjunto de funciones, probablemente no sea el fin del mundo. Pero si el objeto contiene un montón de otros objetos, al instanciarlo va a llamar a todos sus constructores (y destructores, cuando se elimine) y puede obtener fragmentación de memoria, etc.

Dicho esto, no parece que el rendimiento sea su mayor problema en este momento.

9

He tratado un problema similar donde trabajo. El programador antes que yo creó 1 clase de controlador donde todas las funciones BLL fueron abandonadas.

Estamos rediseñando el sistema ahora y hemos creado muchas clases de Controlador según lo que se supone que deben controlar, p.

UserController, GeographyController, ShoppingController ...

Dentro de cada clase controlador que tienen métodos estáticos que hacen llamadas a la caché o el DAL usando el patrón Singleton.

Esto nos ha dado 2 ventajas principales. Es un poco más rápido (alrededor de 2-3 veces más rápido, pero hablaban nanosegundos aquí; P). La otra es que el código es mucho más limpio

es decir

ShoppingController.ListPaymentMethods() 

en lugar de

new ShoppingController().ListPaymentMethods() 

creo que tiene sentido utilizar los métodos estáticos o clases si la clase no mantiene ningún estado .

5

Debe determinar los objetivos de la reescritura. Si desea tener un buen código OO extensible y comprobable &, entonces puede tratar de usar objetos y sus métodos de instancia. Después de todo esto, estamos hablando de programación orientada a objetos, no de programación orientada a clases.

Es muy sencillo simular y/o simular objetos cuando define clases que implementan interfaces y ejecuta métodos de instancia. Esto hace que las pruebas unitarias exhaustivas sean rápidas y efectivas.

Además, si debe seguir los buenos principios de OO (consulte SOLID en http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) y/o utilizar patrones de diseño, seguramente realizará una gran cantidad de desarrollos basados ​​en instancias y no utilizará muchos métodos estáticos.

En cuanto a esta sugerencia:

Parece tonto para mí para crear un objeto sólo para que pueda llamar a un método que aparentemente no tiene efectos secundarios sobre el objeto (de su descripción Asumo que esto)

veo esto mucho en las tiendas de la red del punto y para mí esto viola la encapsulación, un concepto clave OO. No debería poder decir si un método tiene efectos secundarios ya sea que el método sea estático o no. Además de romper la encapsulación, esto significa que tendrá que cambiar los métodos de estático a instancia si/cuando los modifica para tener efectos secundarios. Le sugiero que lea sobre el principio Abierto/Cerrado para este y vea cómo el enfoque sugerido, citado anteriormente, funciona con eso en mente.

Recuerda esa vieja castaña, "la optimización prematura es la raíz de todo mal". Creo que en este caso, esto significa no saltar a través de aros usando técnicas inapropiadas (es decir, programación orientada a la clase) hasta que sepa que tiene un problema de rendimiento. Incluso entonces, resuelva el problema y busque el más apropiado.

2

Los métodos estáticos son mucho más rápidos y utilizan mucha menos memoria. Existe la idea errónea de que es un poco más rápido. Es un poco más rápido siempre y cuando no lo pongas en los bucles. Por cierto, algunos bucles parecen pequeños, pero realmente no lo son porque la llamada al método que contiene el bucle también es otro bucle. Puede ver la diferencia en el código que realiza funciones de representación. Mucho menos memoria es desafortunadamente cierta en muchos casos. Una instancia permite compartir fácilmente la información con métodos hermanos. Un método estático le pedirá la información cuando la necesite.

Pero al igual que en la conducción de automóviles, la velocidad aporta responsabilidad. Los métodos estáticos generalmente tienen más parámetros que su contraparte de instancia. Debido a que una instancia se ocuparía de almacenar en caché las variables compartidas, sus métodos de instancia se verán más bonitos.

ShapeUtils.DrawCircle(stroke, pen, origin, radius); 

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length); 

VS

ShapeUtils utils = new ShapeUtils(stroke,pen); 

util.DrawCircle(origin,radius); 

util.DrawSquare(x,y,width,length); 

En este caso, siempre que las variables de instancia son utilizados por todos los métodos de la mayoría de las veces, los métodos de instancia son bastante pena. Las instancias NO SON SOBRE EL ESTADO, se trata de COMPARTIR aunque el ESTADO COMÚN es una forma natural de COMPARTIR, NO SON LAS MISMAS. La regla general es la siguiente: si el método está estrechamente relacionado con otros métodos, se aman tanto que cuando se llama a uno se necesita llamar al otro y probablemente comparten la misma taza de agua. -, debe hacerse instancia. Traducir métodos estáticos en métodos de instancia no es tan difícil. Solo necesita tomar los parámetros compartidos y ponerlos como variables de instancia. A la inversa, es más difícil.

O puede hacer una clase de proxy que puenteará los métodos estáticos. Si bien puede parecer más ineficiente en teoría, la práctica cuenta una historia diferente. Esto se debe a que siempre que necesite llamar a DrawSquare una vez (o en un bucle), irá directamente al método estático. Pero cada vez que lo vayas a usar una y otra vez junto con DrawCircle, vas a usar el proxy de instancia. Un ejemplo son las clases System.IO FileInfo (instancia) vs File (estática).

Los métodos estáticos son verificados. De hecho, es más comprobable que una vez. El método GetSum (x, y) sería muy comprobable no solo con la prueba unitaria, sino también con la prueba de carga, la prueba integrada y la prueba de uso. Los métodos de instancia son buenos para las pruebas de unidades, pero son horribles para todas las demás pruebas (lo cual es más importante que las pruebas de unidades por cierto) y es por eso que tenemos tantos errores en estos días. Lo que hace que TODOS los métodos no sean comprobables son parámetros que no tienen sentido como (Sender s, EventArgs e) o estado global como DateTime.Now. De hecho, los métodos estáticos son tan buenos para probar que ves menos errores en el código C de una nueva distribución Linux que tu programador OO promedio (está lleno de s *** lo sé).

Cuestiones relacionadas