2010-10-11 28 views
36

Quiero medir la ejecución de un código y me pregunto cuál es el mejor método para hacerlo?Mida el tiempo de ejecución en C#

Opción 1:

DateTime StartTime = DateTime.Now; 

//Code 

TimeSpan ts = DateTime.Now.Subtract(StartTime); 
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
Console.WriteLine(elapsedTime, "RunTime"); 

Opción 2: usando System.Diagnostics;

Stopwatch stopWatch = new Stopwatch(); 
    stopWatch.Start(); 

    //Code 

    stopWatch.Stop(); 
    // Get the elapsed time as a TimeSpan value. 
    TimeSpan ts = stopWatch.Elapsed; 

    // Format and display the TimeSpan value. 
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
    Console.WriteLine(elapsedTime, "RunTime"); 

Esto no es solo para la evaluación comparativa, es realmente parte de la aplicación. El tiempo que tarda la función en ejecutarse es información relevante. Sin embargo, no es necesario que sea atómico o hiper-preciso.

¿Qué opción es mejor para el código de producción, o alguien más usa algo diferente y quizás mejor?

+0

Buena pregunta! Tengo curiosidad en cuanto a la respuesta! –

Respuesta

28

La clase Stopwatch está diseñado específicamente para medir el tiempo transcurrido y pueden (si está disponible en su hardware) proporcionan buena granularidad/precisión usando un temporizador de hardware de alta frecuencia subyacente. Así que esta parece ser la mejor opción.

El IsHighResolution property se puede utilizar para determinar si la sincronización de alta resolución está disponible. Por la documentación, esta clase ofrece un envoltorio en los 'mejores disponibles' API de Win32 para la sincronización exacta:

En concreto, el Frequency campo y GetTimestamp método puede ser utilizado en lugar de los no administrados Win32 API QueryPerformanceFrequency y QueryPerformanceCounter.

Se detallan los antecedentes de las API de Win32 [aquí] y en los documentos de MSDN vinculados 2.

de alta resolución del temporizador

Un contador es un término general utilizado en programación para hacer referencia a una variable de incrementar . Algunos sistemas incluyen un contador de rendimiento de alta resolución que proporciona alta resolución veces transcurridas.

Si existe una actuación contador de alta resolución sobre el sistema, puede utilizar la función QueryPerformanceFrequency para expresar la frecuencia, en cuentas por segundo. El valor del recuento depende del procesador. En algunos procesadores , por ejemplo, el recuento podría ser la velocidad de ciclo del reloj del procesador .

El QueryPerformanceCounter función recupera el valor actual del contador de rendimiento alta resolución. Al llamar a esta función en el al comienzo y al final de una sección del código , una aplicación utiliza esencialmente el contador como un temporizador de alta resolución . Por ejemplo, suponga que QueryPerformanceFrequency indica que la frecuencia del contador de rendimiento de alta resolución es 50,000 cuentas por segundo. Si la aplicación llama QueryPerformanceCounter inmediatamente antes e inmediatamente después de la sección de código a ser programado, los valores de los contadores podrían ser 1500 conteos y 3500 recuentos, respectivamente. Estos valores indicarían que(2000 conteos) transcurrieron mientras se ejecutaba el código .

+0

'Cronómetro' también usa el temporizador de alta resolución (cuando está disponible), que es esencial al medir el código con cortos tiempos de ejecución. – Justin

+0

@Kragen - eso es lo que quise decir sobre el temporizador subyacente. Voy a aclarar por referencia a las API de Win32. –

+0

Tenga en cuenta que es 'Cronómetro' y no' Cronómetro' (menor, lo sé, pero las dependencias de autoresolving no funcionarán si se equivoca). –

5

Tampoco dañará el rendimiento, porque dices que no es tan crítico. StopWatch parece más apropiado: solo resta tiempo del tiempo y no una fecha de otro. La información de fecha requiere un poco más de memoria y tiempo de CPU para tratar. También hay formas de hacer que el código sea más limpio, en caso de que planee reutilizarlo en varios lugares. Sobrecarga de using viene a la mente. Buscaré un ejemplo. Ok, código robado de:

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable 
{ 
    private readonly Stopwatch _stopWatch; 

    public ConsoleAutoStopWatch() 
    { 
     _stopWatch = new Stopwatch(); 
     _stopWatch.Start(); 
    } 

    public void Dispose() 
    { 
     _stopWatch.Stop(); 
     TimeSpan ts = _stopWatch.Elapsed; 

     string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
              ts.Hours, ts.Minutes, ts.Seconds, 
              ts.Milliseconds/10); 
     Console.WriteLine(elapsedTime, "RunTime"); 
    } 
} 

private static void UsingStopWatchUsage() 
{ 
    Console.WriteLine("ConsoleAutoStopWatch Used: "); 
    using (new ConsoleAutoStopWatch()) 
    { 
     Thread.Sleep(3000); 
    } 
} 
+0

No creo que tome más tiempo. Creo que es menos preciso ya que no está hecho para este tipo de medición. – codekaizen

6

Yo generalmente uso StopWatch para este tipo de situación.

De MSDN página:

cronómetro

proporciona un conjunto de métodos y propiedades que se pueden utilizar para medir con precisión el tiempo transcurrido.

En el siguiente post lo uso para comparar el tiempo de ejecución de LINQ vs PLINQ:

Parallel LINQ (PLINQ) with Visual Studio 2010

+0

+1 para el enlace a MSDN donde encontré que parece que el nombre ha cambiado de 'Cronómetro' a' Cronómetro' –

1

Es probable que ambos se adapten a sus necesidades, pero yo diría que use StopWatch. ¿Por qué? Porque es para la tarea que estás haciendo.

Tienes una clase creada para devolver la fecha/hora actual, que puede ser utilizada para cronometrar las cosas, y tienes una clase específicamente diseñada para cronometrar cosas.

En este caso las diferencias solo existen realmente si necesita una precisión de milisegundos (en cuyo caso StopWatch es más preciso), pero como principal general si existe una herramienta específica para la tarea que está buscando, entonces es la mejor usar.

13

No es solo que StopWatch es más preciso, sino también que DateTime.Now dará resultados incorrectos en algunas circunstancias.

considere lo que sucede durante una hora de verano de conmutación, por ejemplo usando — DateTime.Now realidad puede dar una respuesta negativa!

1

Tengo un poco de clase para hacer este tipo de cosas ad hoc.Utiliza la clase de cronómetro - c# micro perfomance testing.

por ejemplo.

var tester = new PerformanceTester(() => SomeMethod()); 
tester.MeasureExecTime(1000); 
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds)); 
0

Uso continuación Código

DateTime dExecutionTime; 
dExecutionTime = DateTime.Now; 
     TimeSpan span = DateTime.Now.Subtract(dExecutionTime); 
        lblExecutinTime.Text = "total time taken " + Math.Round(span.TotalMinutes,2) + " minutes . >>---> " + DateTime.Now.ToShortTimeString(); 
0

Tomé respuesta de Hamish simplifica y lo hizo un poco más general en caso de tener que conectarse a otro lugar:

public class AutoStopWatch : Stopwatch, IDisposable { 

    public AutoStopWatch() { 
     Start(); 
    } 

    public virtual void Dispose() { 
     Stop(); 
    } 
} 

public class AutoStopWatchConsole : AutoStopWatch { 

    private readonly string prefix; 

    public AutoStopWatchConsole(string prefix = "") { 
     this.prefix = prefix; 
    } 

    public override void Dispose() { 
     base.Dispose(); 

     string format = Elapsed.Days > 0 ? "{0} days " : ""; 
     format += "{1:00}:{2:00}:{3:00}.{4:00}"; 

     Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds/10)); 
    } 
} 

private static void Usage() { 

    Console.WriteLine("AutoStopWatch Used: "); 
    using (var sw = new AutoStopWatch()) { 
     Thread.Sleep(3000); 

     Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'")); 
    } 

    Console.WriteLine("AutoStopWatchConsole Used: "); 
    using (var sw = new AutoStopWatchConsole()) { 
     Thread.Sleep(3000); 
    } 

} 
Cuestiones relacionadas