Calculer le temps d'exécution d'une méthode

533

Duplicata possible:
comment mesurer la durée d'exécution d'une fonction?

J'ai une méthode de prise d'E / S qui copie les données d'un emplacement à un autre. Quelle est la façon la meilleure et la plus réelle de calculer le temps d'exécution? Thread? Timer? Stopwatch? Une autre solution? Je veux la plus exacte et la plus brève possible.

Mahdi Tahsildari
la source

Réponses:

1131

Stopwatch est conçu à cet effet et est l'un des meilleurs moyens de mesurer l'exécution du temps dans .NET.

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

N'utilisez pas DateTime pour mesurer l'exécution de l'heure dans .NET.


MISE À JOUR:

Comme indiqué par @ series0ne dans la section des commentaires: Si vous voulez une mesure vraiment précise de l'exécution de certains codes, vous devrez utiliser les compteurs de performances intégrés au système d'exploitation. La réponse suivante contient un bel aperçu.

Darin Dimitrov
la source
2
Exactement, et qu'en est-il de ce cas: j'ai une boucle foreach qui a un ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); intérieur, mais le chronomètre s'arrête avant que tout ne soit fait.
Mahdi Tahsildari
13
@DarinDimitrov - Le chronomètre n'est pas tout à fait exact? rappelez-vous que le bruit de fond .NET (tel que JITing) entraîne des temps d'exécution variables. Par conséquent, de façon réaliste, pour des mesures précises, l'OP devrait utiliser un profileur de performances.
Matthew Layton
3
@ series0ne, très bon point. Je mettrai à jour ma réponse pour inclure votre précieux commentaire.
Darin Dimitrov
7
@DarinDimitrov, j'ai récemment eu un entretien avec un développeur senior très qualifié. Il m'a fait remarquer que l'utilisation de DateTimes est en fait plus précise que l'utilisation d'un chronomètre. Il a dit que la raison en était que le chronomètre dans .NET ne prend pas en compte l'affinité CPU, et donc, si votre thread se déplace d'un cœur à un autre, le chronomètre ne prend pas en compte le temps d'exécution sur les autres cœurs; seul celui où le thread a commencé son exécution. Quelle est ton opinion à ce propos?
Matthew Layton
2
@ series0ne, ce que le développeur principal vous a dit sur le chronomètre et la date et l'heure est absolument vrai. Sauf qu'avec DateTime, vous n'avez pas assez de précision. Le problème est qu'il n'existe aucune classe de ce type dans .NET qui vous permettrait toutes ces fonctionnalités.
Darin Dimitrov
75

Par expérience personnelle, la System.Diagnostics.Stopwatchclasse peut être utilisée pour mesurer le temps d'exécution d'une méthode, cependant ATTENTION : elle n'est pas tout à fait exacte!

Prenons l'exemple suivant:

Stopwatch sw;

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

sw.Stop();

Exemples de résultats

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

Vous vous demandez maintenant; "eh bien pourquoi a-t-il fallu 132 ms la première fois, et nettement moins le reste du temps?"

La réponse est que Stopwatchcela ne compense pas l'activité de «bruit de fond» dans .NET, comme JITing. Par conséquent, la première fois que vous exécutez votre méthode, .NET JIT est la première. Le temps nécessaire pour ce faire s'ajoute au temps de l'exécution. De même, d'autres facteurs feront également varier le temps d'exécution.

Ce que vous devriez vraiment rechercher pour une précision absolue, c'est le profilage des performances !

Jetez un œil à ce qui suit:

RedGate ANTS Performance Profiler est un produit commercial, mais produit des résultats très précis. - Boostez les performances de vos applications avec le profilage .NET

Voici un article StackOverflow sur le profilage: - Quels sont les bons profileurs .NET?

J'ai également écrit un article sur le profilage des performances à l'aide du chronomètre que vous voudrez peut-être consulter - Profilage des performances dans .NET

Matthew Layton
la source
2
@mahditahsildari Aucun problème. Heureux d'avoir pu aider! :-)
Matthew Layton
41
Je ne sais pas pourquoi c'est un exemple d' inexactitude . Le chronomètre mesure avec précision le coût total du premier appel, ce qui est sûrement ce qui est pertinent pour le client qui va exécuter ce code. Ils ne se soucient pas de savoir si ces 132 millisecondes sont imputées à l'exécution de la méthode ou à la gigue, ils se soucient du temps total écoulé.
Eric Lippert
2
@ series0ne Si vous vous souciez des performances d'une boucle, alors mesurez les performances d'une boucle. Ne supposez pas simplement que faire quelque chose n fois signifie que ce sera exactement n fois plus lent que de l'exécuter une fois.
svick
3
Tout d'abord, l'exemple de code devrait produire la sortie avec un nombre toujours croissant car StopWatch n'est jamais réinitialisé dans la boucle. Et par "devrait" je veux dire que c'est le cas (j'ai vérifié). Votre sortie ne correspond donc pas au code. Deuxièmement, lorsque j'ai corrigé le code pour faire un arrêt / écriture / réinitialisation / démarrage dans la boucle, la première mesure était la même que les autres. Je suppose que votre DoSomething fait quelque chose plus longtemps la première fois qu'il s'exécute. JIT peut être ou non la raison, mais ce n'est pas que le chronomètre affecte la mesure. D'où -1.
ILIA BROUDNO
2
ILIA BROUDNO est absolument correcte, j'ai obtenu les mêmes résultats. @ series0ne, vous avez une Console.WriteLine dans la boucle, écrivant le ms jusqu'à présent; parce que vous n'arrêtez la montre qu'après la fin de la boucle, elle augmente avec le temps à chaque itération, nous devrions donc voir quelque chose comme 3, 6, 10, 12, 15 ... à mesure que le temps s'accumule au fil des exécutions.
Rui Miguel Pinheiro
29

StopWatch la classe recherche votre meilleure solution.

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

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

Il a également un champ statique appelé Stopwatch.IsHighResolution. Bien sûr, il s'agit d'un problème de matériel et de système d'exploitation.

Indique si le minuteur est basé sur un compteur de performances haute résolution.

Soner Gönül
la source
18

Si vous souhaitez comprendre les performances, la meilleure réponse consiste à utiliser un profileur.

Sinon, System.Diagnostics.StopWatch fournit une minuterie haute résolution.

Jeff Foster
la source
Absolument correct! Je suis un peu découragé que tant de personnes ici aient suggéré d'utiliser le chronomètre, car il n'est pas tout à fait exact. Cependant, comme vous l'avez suggéré d'utiliser un profileur de performances, c'est la bonne façon de le faire! +1
Matthew Layton
7

StopWatch utilisera le compteur haute résolution

Le chronomètre mesure le temps écoulé en comptant les tics du minuteur dans le mécanisme de minuteur sous-jacent. Si le matériel et le système d'exploitation installés prennent en charge un compteur de performances haute résolution, la classe Chronomètre utilise ce compteur pour mesurer le temps écoulé. Sinon, la classe Chronomètre utilise le minuteur système pour mesurer le temps écoulé. Utilisez les champs Frequency et IsHighResolution pour déterminer la précision et la résolution de l'implémentation du chronométrage.

Si vous mesurez les E / S, vos chiffres seront probablement affectés par des événements externes, et je m'inquiéterais tellement. exactitude (comme vous l'avez indiqué ci-dessus). Au lieu de cela, je prendrais une gamme de mesures et considérerais la moyenne et la distribution de ces chiffres.

Brian Agnew
la source
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
la source