2012-03-06 12 views
8

Tengo el siguiente código:palabra clave 'nueva' en getter> impacto en el rendimiento?

public class Character 
{ 
    public Vector2 WorldPixelPosition 
    { 
     get { return Movement.Position; } 
    } 
    public Vector2 WorldPosition 
    { 
     get { return new Vector2(Movement.Position.X/Tile.Width, Movement.Position.Y/Tile.Height); } 
    } 
    public Vector2 LevelPosition 
    { 
     get { return new Vector2(WorldPosition.X % Level.Width, WorldPosition.Y % Level.Height); } 
    } 
} 

Ahora en otra parte de mi código, que alrededor de 2500 llamadas en un bucle para Character.LevelPosition. Esto significa que por cada ciclo de actualización, se están haciendo 5000 'nuevos' Vector2s, y en mi computadora portátil, realmente baja la velocidad de cuadros.

he fijado temporalmente mediante la creación de

var levelPosition = Character.LevelPosition; 

antes de que inicio del bucle, pero me siento un poco su código feo para hacer esto cada vez que me encuentro con una situación similar. Tal vez, es el camino a seguir, pero quiero asegurarme.

¿Existe una forma mejor o comúnmente aceptada de hacer esto?

Estoy usando el XNA-Framework, que usa Vector2 's.

+0

¿Es 'Vector2' una 'clase'? No hay mucho código aquí, pero parece que podría (¿debería?) Ser una "estructura", en cuyo caso debería funcionar mucho mejor. En cualquier caso, la solución que mencionas es una optimización totalmente válida, ya que sabes de hecho qué es lo que te está frenando. – Jon

+0

Oh, lo siento. Estoy trabajando en el XNA-Framework, debería haberlo mencionado. – Taelia

+0

¿De verdad necesitas hacer eso 2500 veces? ¿No se puede cortar para, por ejemplo, el área visible? – CodeCaster

Respuesta

5

Por lo que entiendo, debe evitar la asignación de muchos objetos del montón en XNA, porque eso causa un mal rendimiento. Pero dado que Vector2 es struct, no estamos asignando nada en el montón aquí, por lo que ese no debería ser el problema aquí.

Ahora, si tiene un ciclo cerrado, como lo hace, en una aplicación de rendimiento crítico, como un juego, siempre tendrá que pensar en el rendimiento, no hay vuelta atrás.

Si miramos el código para LevelPosition, llame al captador para WorldPosition dos veces y probablemente algunos captadores más. El getter para WorldPosition probablemente llama a algunos otros getters. (Es difícil decir qué está sucediendo exactamente sin tener la fuente, porque la llamada directora y el acceso de campo se ven exactamente iguales.)

Llamar a un comprador, que en realidad es solo una llamada a un método especial, suele ser bastante rápido y puede ser incluso más rápido si el compilador decide usar la alineación.Pero todas las llamadas se suman juntas, especialmente si las llamas en un bucle.

La solución para esto es algún tipo de almacenamiento en caché. Una opción sería hacer de LevelPosition un campo e idear un sistema para actualizarlo cuando sea necesario. Esto podría funcionar, pero también podría perjudicar el rendimiento si necesita actualizarlo con más frecuencia de lo que lo lee.

Otra solución es, como descubriste, almacenar en caché el resultado en una variable local. Si sabe que esto es correcto, es decir, que el valor de la propiedad no cambiará durante la ejecución del bucle, ¡eso es increíble! Resolvió su problema de rendimiento y lo hizo con solo una línea de código que es fácilmente comprensible para cualquier programador. ¿Qué más quieres?

Permítanme repetir eso. Encontraste una solución a su problema de rendimiento que:

  1. obras
  2. es simple de implementar
  3. es fácil de entender

creo que tal solución Wold ser muy difícil de superar.

+0

Muy bien, esta es también una respuesta muy clara. Jugaré un poco más con estas soluciones y descubriré qué funciona mejor para mí. ¡Gracias a ti también! – Taelia

2

Puede crear un campo privado para almacenar el valor y no calcularlo cada vez. Puede crear un método para actualizar los campos privados y suscribirse para el Movimiento. La posición cambia de alguna manera. De esta forma, el valor se calculará solo una vez cuando la posición cambie.

+0

La suscripción puede funcionar, pero ¿no es una gran cantidad de gastos cada vez que me encuentro con una situación similar? – Taelia

+0

gastos generales de rendimiento o gastos generales de codificación? Dudo que sea una sobrecarga de rendimiento ya que necesita actualizar los valores de todos modos. En la codificación ... ciertamente lo es. Tal vez puedas usar alguna clase base genérica para aliviar la situación. – Stilgar

4

Crear muchos objetos en un bucle puede ser una operación costosa (*). Tal vez si ayudaría a crear el Vector2 por adelantado (por ejemplo, cuando las coordenadas cambian) y en el futuro simplemente cambie las coordenadas.

Ejemplo:

public class Character 
{ 
    private Vector2 m_worldPosition = new Vector2(0, 0); 
    private Vector2 m_levelPosition = new Vector2(0, 0); 

    .... 

    public Vector2 WorldPosition 
    { 
     get 
     { 
      m_worldPosition.X = ...; 
      m_worldPosition.Y = ...; 
      return m_worldPosition; 
     } 
    } 

    public Vector2 LevelPosition 
    { 
     get 
     { 
      m_levelPosition.X = ...; 
      m_levelPosition.Y = ...; 
      return m_levelPosition; 
     } 
    } 
} 

EDITAR
El mismo debe hacerse para la propiedad LevelPosition también. Ver código fuente modificado.

(*)
Tim Schmelter me señaló a this question con una discusión detallada sobre el impacto de objetos instanciar. He reformulado mi oración inicial de que la creación del objeto es siempre caro. Si bien la creación de objetos no siempre es una operación costosa, puede ralentizar el rendimiento en ciertos casos.

+0

Creo que esta es una gran idea. En realidad, podría haber aumentado su rendimiento sobre mi solución original. ¡Gracias! – Taelia

+0

Acepto que debe poder almacenar los valores y solo actualizarlos cuando sea necesario. – cgatian

+1

Cuando hablamos de problemas de velocidad, la creación de objetos siempre es un buen punto de partida para acelerar las cosas. Me alegro de poder ayudar. –

Cuestiones relacionadas