Misurare il tempo di esecuzione in C#
-
29-09-2019 - |
Domanda
Voglio misurare l'esecuzione di un pezzo di codice e mi chiedo che cosa è il metodo migliore per fare questo?
Opzione 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");
Opzione 2:utilizzando Sistema.La diagnostica;
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");
Questo non è semplicemente per il benchmarking, in realtà fa parte dell'applicazione.La volta che la funzione richiede per l'esecuzione pertinenti dati.Non ha tuttavia bisogno di essere atomica o precisi.
Quale opzione è meglio per il codice di produzione, o c'è qualcun altro di utilizzare qualcosa di diverso e forse migliore?
Soluzione
La classe Stopwatch
è specificamente progettato per misurare il tempo trascorso e può (se disponibile sul proprio hardware) fornire una buona granularità / precisione utilizzando un timer sottostante hardware ad alta frequenza. Quindi questo sembra la scelta migliore.
Il IsHighResolution proprietà può essere utilizzato per determinare se temporizzazione ad alta risoluzione è disponibile. Per la documentazione, questo offre un wrapper di classe sul 'migliore disponibile' API Win32 per la temporizzazione precisa:
In particolare, il campo
Frequency
e MetodoGetTimestamp
può essere utilizzato in posto del non gestito Win32 APIQueryPerformanceFrequency
eQueryPerformanceCounter
.
Non c'è sfondo dettagliate su quelli Win32 API [qui] e nella documentazione MSDN legate 2 .
ad alta risoluzione del timer
Un contatore è un termine generico usato in programmazione per fare riferimento a un incremento variabile. alcuni sistemi includere una performance ad alta risoluzione contatore che fornisce ad alta risoluzione trascorsi i tempi.
Se una performance ad alta risoluzione contatore esiste sul sistema, è possibile utilizzare il QueryPerformanceFrequency funzione di esprimere la frequenza, in conteggi per secondo. Il valore della conteggio è processore dipendente. su alcuni processori, per esempio, il conteggio potrebbe essere il tasso di ciclo del di clock del processore.
QueryPerformanceCounter Funzione recupera il valore corrente della alta risoluzione contatore di prestazioni. Chiamando questa funzione al inizio e fine di una sezione di codice, un'applicazione utilizza essenzialmente il contatore come ad alta risoluzione Timer. Per esempio, supponiamo che QueryPerformanceFrequency indica che la frequenza del contatore di prestazioni ad alta risoluzione è 50.000 conteggi per secondo. Se la le chiamate di applicazione QueryPerformanceCounter immediatamente prima e subito dopo la sezione di codice sia programmata, la i valori del contatore potrebbero essere 1500 conta e 3500 conteggi, rispettivamente. Questi valori indicherebbero che .04 secondi (2000 conteggi) trascorso mentre il codice eseguito.
Altri suggerimenti
Non è solo che StopWatch
è più preciso, ma anche che DateTime.Now
darà risultati non corretti in alcune circostanze.
Considerare ciò che accade durante l'ora legale switch-over, per esempio utilizzando DateTime.Now
può effettivamente dare un negativo la risposta!
Io in genere uso StopWatch
per questo tipo di situazione.
Da pagina MSDN :
Cronometro
Fornisce un insieme di metodi e le proprietà che è possibile utilizzare per misurare con precisione il tempo trascorso.
Nel seguente post Io lo uso per confrontare il tempo di esecuzione di LINQ vs PLINQ:
Né farà male le prestazioni, perché si dice che non è così critica. StopWatch sembra più appropriato - si sta solo il tempo di tanto e non uno da un altro data sottrarre. Data roba prende un po 'più di memoria e CPU tempo per affrontare. Ci sono anche modi per rendere il codice più pulito, nel caso in cui si prevede di riutilizzare in più punti. Il sovraccarico using
viene in mente. Cercherò un esempio. Ok, il codice rubato da:
http://stevesmithblog.com/blog/great -Utilizza-di-uso-dichiarazione-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);
}
}
Entrambi saranno probabilmente soddisfare le vostre esigenze più che bene, ma direi uso StopWatch
. Perché? Causa è significato per l'attività che si sta facendo.
Hai una classe che è costruito per restituire la data / ora corrente, che, come accade può essere utilizzato per le cose temporali, e hai una classe specificamente progettato per le cose temporali.
In questo caso le differenze esistono veramente solo se avete bisogno di precisione millisecondo (nel qual caso StopWatch
è più preciso), ma come un principio generale, se uno strumento esiste specificamente per l'attività che stai cercando allora è il migliore per uso.
Ho un po 'di classe per fare questo genere di cose ad hoc. Esso utilizza la classe cronometro - c # micro perfomance test .
ad es.
var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));
L'uso di sotto codice
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();
Ho preso la risposta di Hamish semplificato e reso un po 'più generale nel caso in cui devi effettuare il login da qualche altra parte:
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);
}
}