MySimpleWatch : mesurer un temps d’ exécution simplement avec StopWatch
Introduite dans la version 2.0 du framework, la classe StopWatch (dans l’ espace de nom System.Diagnostic) permet de mesurer facilement et d’ une grande précision de l’ ordre de la microseconde (0.000001 seconde).
Cette classe n’ est qu’ une abstraction de ce que l’ on devait faire avant sous .NET 1.x en utilisant la méthode QueryPerformanceCounter via un DllImport de kernel32.dll, simplifiant ainsi la mesure de temps. (En quelque sorte, une amélioration de ma classe PerfTimer que j’ avais utilisé pour mesurer mon algo de résolution de Mastermind il y a déjà quelques années ^^).
L’ utilisation de StopWatch est très simple. On crée notre objet StopWatch pour pouvoir appeler les méthodes Start et Stop qui vont respectivement permettre de démarrer et arrêter notre timer et on récupère le temps écoulé via les propriétés Elapsed, ElapsedMilliseconds, ou ElapsedTicks. (documentation MSDN de StopWatch).
Exemple très simple :
1 2 3 4 5 | StopWatch stopWatch = new StopWatch(); stopWatch.Start(); // -- Code à mesurer ici -- stopWatch.Stop(); Console.WriteLine("Temps écoulé en ms : " + stopWatch.ElapsedMilliseconds.ToString()); |
Maintenant introduit à l’ objet StopWatch pour ceux qui ne connaissaient pas, revenons sur MySimpleWatch ! Historiquement, j’ avais réalisé l’ an passé une petite classe, enfin du moins une simple méthode dans un de mes projets, permettant grâce aux délégués et méthodes anonymes introduits dans C#2.0 d’ exécuter du code avant et après mon délégué. Plus récemment, mardi dernier, pendant une session sur « LINQ avancé » aux TechDays 2008, Mitsu nous donnait dans la même lignée une astuce pour démarrer/arrêter un StopWatch, ce qui m’ a donné l’ envie de récrire cela dans une belle classe que je pourrais utiliser un peu partout dans mes développements.
L’ idée est très simple : avoir une méthode prenant en paramètre une Action (code à exécuter) que l’ on mesurera. En résumé :
1 2 3 | stopWatch.Start(); action(); stopWatch.Stop(); |
De plus, j’ ai ajouté la possibilité de passer un deuxième délégué dans cette méthode de type Action<Stopwatch> qui sera exécuté à la fin pour traiter le résultat du timer (par exemple pour écrire le résultat dans un log, Trace, etc…).
Le code de ma classe étant très simple, je ne rentre pas plus sur son explication, mais voyons plutôt son utilisation dans notre code.
MySimpleWatch contient trois méthodes publiques :
- SimpleWatch : permet simplement d’ exécuter un bout de code en nous renvoyant un StopWatch contenant le temps d’ exécution de ce code.
- DisplayWatch : exécute le code de l’Action et affiche le résultat dans la Console. (avec possibilité de donner un nom à la tache – utile si plusieurs résultats sont affichés dans la console !)
- ProcessWatch : exécute le code de l’Action comme toujours puis exécute le deuxième délégué pour traiter la réponse en passant en paramètre le StopWatch du résultat (en clair un Action<Stopwatch>)
Rien ne vaut de bons exemples :
1) Afficher simplement la mesure dans la console :
1 2 3 4 5 6 7 | MySimpleWatch watch = new MySimpleWatch(); watch.DisplayWatch(delegate { // Code à mesurer ici ! Ex : Thread.Sleep(1000); }); |
2) Obtenir le StopWatch d’un bout de code :
1 2 3 4 5 6 7 8 9 10 | MySimpleWatch watch = new MySimpleWatch(); var result = watch.SimpleWatch(delegate { // Code à mesurer ici ! Ex : Thread.Sleep(1000); }); // Exemple de traitement du resultat : Trace.WriteLine("Elapsed time in ms : " + result.ElapsedMilliseconds.ToString()); |
3) Exécuter du code pour traiter le résultat :
1 2 3 4 5 6 7 8 9 10 11 12 13 | MySimpleWatch watch = new MySimpleWatch(); watch.ProcessWatch(delegate { // Code à mesurer ici ! Ex : Thread.Sleep(1000); }, delegate(Stopwatch w) { // Code pour traiter le resultat ici ! // Exemple: Trace.WriteLine("Elapsed time in ms : " + w.ElapsedMilliseconds.ToString()); }); |
En utilisant les expressions lambda introduitent dans C# 3.0, nous pouvons aussi simplifier le code par :
1 2 3 4 5 6 7 | MySimpleWatch watch = new MySimpleWatch(); watch.ProcessWatch(delegate { // Code à mesurer ici ! Ex : Thread.Sleep(1000); }, (w => Trace.WriteLine("Elapsed time in ms : " + w.ElapsedMilliseconds.ToString()))); |
Voilà, j’ espère que cela pourra vous être utile 🙂 Le code de la classe MySimpleWatch est disponible ici.