2011-01-03 43 views
5

Estoy haciendo problemas de práctica de MCTS Examen 70-536 Microsft .Net Framework Aplicación Dev Foundation, y uno de los problemas es crear dos clases, una genérica, un tipo de objeto que ambos realizan lo mismo ; en el que un ciclo usa la clase e itera más de mil veces. Y usando el temporizador, mide el tiempo de ambos. Hubo otra publicación en C# generics question que busca la misma pregunta pero nadie contestó.Genéricos vs Objeto de rendimiento

Básicamente, si en mi código ejecuto la clase genérica primero, se necesita procesar. Si ejecuto la clase de objeto primero, la clase de objeto tarda más en procesarse. La idea era probar que los genéricos funcionan más rápido.

Utilicé el código de usuario original para ahorrar algo de tiempo. En particular, no vi nada malo con el código y me sorprendió el resultado. ¿Puede alguien explicar por qué los resultados inusuales?

Gracias,

Risho

Aquí está el código:

class Program 
{ 
    class Object_Sample 
    {    
     public Object_Sample() 
     { 
      Console.WriteLine("Object_Sample Class"); 
     } 

     public long getTicks() 
     { 
      return DateTime.Now.Ticks; 
     } 

     public void display(Object a) 
     { 
      Console.WriteLine("{0}", a); 
     } 
    } 

    class Generics_Samle<T> 
    {    
     public Generics_Samle() 
     { 
      Console.WriteLine("Generics_Sample Class"); 
     } 

     public long getTicks() 
     { 
      return DateTime.Now.Ticks; 
     } 

     public void display(T a) 
     { 
      Console.WriteLine("{0}", a); 
     } 
    } 

    static void Main(string[] args) 
    {    
     long ticks_initial, ticks_final, diff_generics, diff_object; 
     Object_Sample OS = new Object_Sample(); 
     Generics_Samle<int> GS = new Generics_Samle<int>(); 

     //Generic Sample 
     ticks_initial = 0; 
     ticks_final = 0; 
     ticks_initial = GS.getTicks(); 

     for (int i = 0; i < 50000; i++) 
     { 
      GS.display(i); 
     } 
     ticks_final = GS.getTicks(); 
     diff_generics = ticks_final - ticks_initial; 

     //Object Sample 
     ticks_initial = 0; 
     ticks_final = 0; 
     ticks_initial = OS.getTicks(); 

     for (int j = 0; j < 50000; j++) 
     { 
      OS.display(j); 
     } 

     ticks_final = OS.getTicks(); 
     diff_object = ticks_final - ticks_initial; 

     Console.WriteLine("\nPerformance of Generics {0}", diff_generics); 
     Console.WriteLine("Performance of Object {0}", diff_object); 

     Console.ReadKey(); 
    } 
} 
+3

Debe aceptar las respuestas a sus preguntas. – SLaks

+1

Deberías usar la clase 'Cronómetro'. – SLaks

+1

Debe hacer clic en la marca vacía al lado de la mejor respuesta dada para cada una de sus preguntas para aceptar esa respuesta. – SLaks

Respuesta

5

Su prueba es incorrecta. Aquí están sus métodos:

public void display(T a) 
{ 
    Console.WriteLine("{0}", a); // Console.WriteLine(string format, params object[] args) <- boxing is performed here 
} 

public void display(Object a)// <- boxing is performed here 
{ 
    Console.WriteLine("{0}", a); 
} 

Por lo tanto, en ambos casos está utilizando el boxeo. Mucho mejor sería si su clase, por ejemplo, contará suma total de los valores, como:

public void add(long a) 
{ 
    Total += a; 
} 

public void display(Object a)// <- boxing is performed here 
{ 
    Total += (long) a;// <- unboxing is performed here 
} 
+0

No escribí este código, solo quería probar lo que el libro ha sugerido. En su comentario, declara que el boxeo de "visualización de vacío público (Objeto a)" se realiza aquí. ¿Puedes explicar eso, por favor? No estoy ocultando aquí nada ¿verdad? – Risho

+0

'long' es el tipo de valor. Cuando está lanzando tipo de valor a un objeto, se llama 'boxeo'. Eso significa que el tipo de valor está envuelto por una 'caja' especial, que es un tipo de referencia. En este momento, .Net necesita asignar memoria para esta 'caja' y esta no es una operación tan rápida. Cuando lanzas el objeto al tipo de valor, se llama 'unboxing', el valor se copia de 'box' a tu variable. Cuando estás llamando al método con el método 'de la firma (objeto a)' .Net realiza el reparto implícito de tu 'largo' a' objeto' y eso produce cierta brecha de rendimiento debido al boxeo. –

+0

Por lo tanto, no importa qué tipo de argumento de entrada esté utilizando en su método 'display', porque en el caso del boxeo de 'objeto' tiene lugar en la llamada al método' display', y en 'generic' en 'Console.WriteLine' llamada de método, pero aún está teniendo lugar. –

8

debería ejecutar ambas clases un tiempo separado antes de sincronización que permite a la fluctuación de fase a ejecutar.

+0

+1 Esto me suena a la trepidación también. –

+0

¿Revisaste su perfil para ver si hay respuestas aceptables? –

+1

@Henk - Creo que después de 13 preguntas, al menos * una * respuesta sería aceptable. Pero nuevamente, la aceptabilidad está en el ojo del espectador. –

3

¿por qué sería más rápido? ambos enteros deben encajonar con el fin de utilizar Console.WriteLine (String, Object)

edición: ToString() en sí no parece causar el boxeo http://weblogs.asp.net/ngur/archive/2003/12/16/43856.aspx

por lo que cuando se utiliza Console.WriteLine (a); que llamaría a Console.WriteLine (Int32) que debería funcionar supongo (necesitaría mirar en el reflector para confirmar esto)

+0

El libro de texto indicó que los genéricos son más rápidos. – Risho

+0

bien, son más rápidos si evitan el boxeo y el desempaquetado, pero ese no es el caso aquí – Kikaimaru

+0

Estoy tratando de entender esto: no estoy convirtiendo nada aquí, a menos que lo haga Console.WriteLines, que no sabía. Si ese es el caso, ¿cómo se muestran los resultados sin "boxeo/unboxing"? – Risho

9

Bueno, el primer problema que puedo ver es que estás usando el objeto DateTime para medir el tiempo en su aplicación (por un intervalo muy pequeño).

Debe utilizar la clase Stopwatch. Ofrece una mayor precisión cuando se trata de comparar el código.

El segundo problema es que no está permitiendo la compilación JIT (Just-In-Time). La primera llamada a su código va a tomar más tiempo simplemente porque tiene que estar JIT. Después de eso, obtendrás tus resultados.

Haría una sola llamada a su código antes de comenzar a cronometrar las cosas para que pueda tener una idea precisa de lo que está sucediendo durante el ciclo.

+1

+1 Para 'Cronómetro' –

3
  1. Su código temporizado incluye un Console.WriteLine(). Eso ocupará el 99.999999% del tiempo.
  2. Su suposición de que los genéricos serán más rápidos en esta situación es incorrecta. Es posible que haya malinterpretado una observación sobre clases de colecciones no genéricas.
  3. Esto no estará en el examen.