Calcular el tiempo de ejecución de un método

Respuestas:

1131

Stopwatch está diseñado para este propósito y es una de las mejores formas de medir la ejecución de tiempo en .NET.

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

No use DateTime para medir la ejecución de tiempo en .NET.


ACTUALIZAR:

Como señaló @ series0ne en la sección de comentarios: si desea una medición real y precisa de la ejecución de algún código, deberá utilizar los contadores de rendimiento integrados en el sistema operativo. La siguiente respuesta contiene una buena descripción general.

Darin Dimitrov
fuente
2
Exactamente, y qué pasa con este caso: tengo un bucle foreach que tiene un ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); interior, pero el cronómetro se detiene antes de que todo esté hecho.
Mahdi Tahsildari
13
@DarinDimitrov - ¿El cronómetro no es del todo exacto? recuerde que el ruido de fondo .NET (como JITing) hace que se produzcan tiempos de ejecución variables. Por lo tanto, de manera realista, para mediciones precisas, el OP debe usar un perfilador de rendimiento.
Matthew Layton
3
@ series0ne, muy buen punto. Actualizaré mi respuesta para incluir su valioso comentario.
Darin Dimitrov
77
@DarinDimitrov, recientemente tuve una entrevista con un desarrollador senior muy calificado. Me señaló que usar DateTimes es en realidad más preciso que usar un StopWatch. Dijo que la razón de esto es que el cronómetro en .NET no tiene en cuenta la afinidad de la CPU y, por lo tanto, si su hilo se mueve de un núcleo a otro, el cronómetro no tiene en cuenta el tiempo de ejecución en los otros núcleos; solo aquel donde el hilo comenzó a ejecutarse. ¿Qué opinas de esto?
Matthew Layton
2
@ series0ne, lo que el desarrollador senior le dijo sobre el cronómetro y DateTime es absolutamente cierto. Excepto que con DateTime no tienes suficiente precisión. El problema es que no existe tal clase en .NET que le permita todas esas características.
Darin Dimitrov
75

Por experiencia personal, la System.Diagnostics.Stopwatchclase se puede usar para medir el tiempo de ejecución de un método, sin embargo, CUIDADO : ¡No es del todo exacto!

Considere el siguiente ejemplo:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

Resultados de ejemplo

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

Ahora te preguntas; "Bueno, ¿por qué tardó 132 ms la primera vez, y significativamente menos el resto del tiempo?"

La respuesta es que Stopwatchno compensa la actividad de "ruido de fondo" en .NET, como JITing. Por lo tanto, la primera vez que ejecuta su método, .NET JIT lo es primero. El tiempo que lleva hacer esto se agrega al tiempo de la ejecución. Igualmente, otros factores también harán que varíe el tiempo de ejecución.

¡Lo que realmente debería estar buscando con absoluta precisión es el perfil de rendimiento !

Echa un vistazo a lo siguiente:

RedGate ANTS Performance Profiler es un producto comercial, pero produce resultados muy precisos. - Aumente el rendimiento de sus aplicaciones con la creación de perfiles .NET

Aquí hay un artículo de StackOverflow sobre creación de perfiles: - ¿Cuáles son algunos buenos perfiles de .NET?

También he escrito un artículo sobre el Perfil de rendimiento usando el cronómetro que es posible que desee ver - Perfil de rendimiento en .NET

Matthew Layton
fuente
2
@mahditahsildari No hay problema. Me alegro de poder ayudar! :-)
Matthew Layton
41
No estoy seguro de por qué este es un ejemplo de inexactitud . El cronómetro mide con precisión el costo total de la primera llamada, que seguramente es lo que es relevante para el cliente que ejecutará este código. No les importa si esos 132 milisegundos se cargan a la ejecución del método o al jitter, les importa el tiempo total transcurrido.
Eric Lippert
2
@ series0ne Si le importa el rendimiento de un bucle, mida el rendimiento de un bucle. No asuma simplemente que hacer algo n veces significa que será exactamente n veces más lento que ejecutarlo una vez.
svick
3
En primer lugar, el ejemplo de código debería producir la salida con un número cada vez mayor ya que StopWatch nunca se restablece en el bucle. Y por "debería" quiero decir que sí (lo comprobé). Entonces su salida no coincide con el código. En segundo lugar, cuando corregí el código para hacer un Stop / Write / Reset / Start en el bucle, la primera medición fue la misma que el resto. Supongo que su DoSomething hace algo por más tiempo la primera vez que se ejecuta. JIT puede o no ser la razón, pero no es que el cronómetro esté afectando la medición. Por lo tanto -1.
ILIA BROUDNO
2
ILIA BROUDNO es absolutamente correcta, obtuve los mismos resultados. @ series0ne, tienes una Console.WriteLine dentro del bucle, escribiendo el ms hasta ahora; porque solo detiene el reloj DESPUÉS de que finaliza el ciclo, aumenta con el tiempo con cada iteración, por lo que deberíamos ver algo así como 3, 6, 10, 12, 15 ... a medida que el tiempo se acumula durante las ejecuciones.
Rui Miguel Pinheiro
29

StopWatch clase busca tu mejor solución.

Stopwatch sw = Stopwatch.StartNew();
DoSomeWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

También tiene un campo estático llamado Stopwatch.IsHighResolution. Por supuesto, este es un problema de hardware y sistema operativo.

Indica si el temporizador se basa en un contador de rendimiento de alta resolución.

Soner Gönül
fuente
18

Si está interesado en comprender el rendimiento, la mejor respuesta es utilizar un generador de perfiles.

De lo contrario, System.Diagnostics.StopWatch proporciona un temporizador de alta resolución.

Jeff Foster
fuente
¡Absolutamente correcto! Estoy un poco desanimado porque tantos aquí han sugerido usar el Cronómetro, ya que no es del todo exacto. Sin embargo, como sugirió usar un perfilador de rendimiento, ¡esta es la forma correcta de hacerlo! +1
Matthew Layton
7

StopWatch usará el contador de alta resolución

El cronómetro mide el tiempo transcurrido contando los tics del temporizador en el mecanismo del temporizador subyacente. Si el hardware y el sistema operativo instalados admiten un contador de rendimiento de alta resolución, la clase Cronómetro usa ese contador para medir el tiempo transcurrido. De lo contrario, la clase Cronómetro usa el temporizador del sistema para medir el tiempo transcurrido. Use los campos Frecuencia e IsHighResolution para determinar la precisión y la resolución de la implementación del cronómetro.

Si está midiendo IO, entonces sus cifras probablemente se verán afectadas por eventos externos, y me preocuparía mucho. exactitud (como has indicado anteriormente). En cambio, tomaría un rango de medidas y consideraría la media y la distribución de esas cifras.

Brian Agnew
fuente
0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
Md.Rakibuz Sultan
fuente