Mesurer le temps d'exécution en C #
-
29-09-2019 - |
Question
Je veux mesurer l'exécution d'un morceau de code et je me demande quelle est la meilleure méthode pour le faire est?
Option 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");
Option 2: en utilisant 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");
Il ne suffit pas pour l'analyse comparative, est en fait une partie de l'application. Le temps de la fonction nécessaire à l'exécution est des données pertinentes. Il n'a cependant pas besoin d'être atomique ou hyper-précis.
Quelle option est préférable pour le code de production, ou que quelqu'un d'autre utiliser quelque chose de différent et peut-être mieux?
La solution
La classe Stopwatch
est spécialement conçu pour mesurer le temps écoulé et peut (si disponible sur votre matériel) fournir une bonne granularité / précision en utilisant une horloge matérielle haute fréquence sous-jacente. Donc, ce semble le meilleur choix.
Le propriété IsHighResolution peut être utilisé pour déterminer si le calendrier haute résolution est disponible. Par la documentation, cette catégorie offre une enveloppe sur le « meilleur disponible » API Win32 pour une synchronisation précise:
Plus précisément, le champ et
Frequency
Procédé deGetTimestamp
peut être utilisé dans la place de l'API Win32 non géréQueryPerformanceFrequency
etQueryPerformanceCounter
.
Il y a fond détaillées sur les API Win32 [ici] et liés docs MSDN 2 .
haute résolution minuterie
Un compteur est un terme général utilisé dans la programmation pour faire référence à un variables incrémenter. certains systèmes inclure une performance haute résolution compteur qui fournit à haute résolution le temps écoulé.
Si une performance à haute résolution compteur existe sur le système, vous pouvez utiliser le QueryPerformanceFrequency fonctionner pour exprimer la fréquence, en comptes par seconde. La valeur de la comptage dépend processeur. Sur quelques processeurs, par exemple, le nombre pourrait être le taux de cycle de la horloge processeur.
QueryPerformanceCounter fonction récupère la valeur courante de la compteur de performance à haute résolution. En appelant cette fonction au début et la fin d'une section de code, une application utilise essentiellement le compteur en haute résolution minuteur. Par exemple, supposons que QueryPerformanceFrequency indique que la fréquence de la compteur de performance à haute résolution est 50.000 comptes par seconde. Si la appels d'application QueryPerformanceCounter immédiatement avant et immédiatement après la section de code pour être programmé, la les valeurs du compteur peut être 1500 compte et 3500 chefs d'accusation, respectivement. Celles-ci les valeurs indiquerait que .04 secondes (2000 points) se sont écoulées alors que le code exécutée.
Autres conseils
Il est pas seulement que StopWatch
est plus précis, mais aussi que DateTime.Now
donnera des résultats incorrects dans certaines circonstances.
Pensez à ce qui se passe pendant un temps de commutation d'été, par exemple - en utilisant DateTime.Now
peut effectivement donner une négatif réponse
J'utilise généralement StopWatch
pour ce genre de situation.
A partir de la page MSDN:
StopWatch
Fournit un ensemble de méthodes et propriétés que vous pouvez utiliser pour mesurer avec précision le temps écoulé.
Dans le post suivant, je l'utilise pour comparer le temps d'exécution de LINQ vs PLINQ:
Ni va nuire à la performance, parce que vous dites est pas critique. StopWatch semble plus approprié - vous ne soustrayez temps de temps et non d'une date d'un autre. choses Date prend un peu plus de mémoire et de temps CPU à traiter. Il y a aussi des façons de rendre le code plus propre, si vous prévoyez qu'il réutiliser dans plusieurs endroits. using
vient à Surcharge esprit. Je recherche un exemple. Ok, le code volé:
http://stevesmithblog.com/blog/great -Utilise-de-utilisant-déclaration en 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);
}
}
Les deux seront probablement s'adapter à vos besoins très bien, mais je dirais que l'utilisation StopWatch
. Pourquoi? Parce que cela signifie pour la tâche que vous faites.
Vous avez une classe qui est construit pour retourner la date / heure actuelle, qui, comme il arrive peut être utilisé pour des choses temporelles, et vous avez une classe spécialement conçu pour les choses temporelles.
Dans ce cas, les différences n'existent vraiment si vous avez besoin de précision milliseconde (Dans ce cas StopWatch
est plus précis), mais comme un principe général si un outil existe spécifiquement pour la tâche que vous cherchez alors il est le meilleur à utilisation.
J'ai une petite classe pour faire ce genre de chose ad hoc. Il utilise la classe chronomètre - c # micro test perfomance .
par exemple.
var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));
Utilisez le code ci-dessous
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();
Je pris la réponse de Hamish simplifiée et fait un peu plus générale dans le cas où vous avez besoin de se connecter à un autre endroit:
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);
}
}