488 votes

DateTime.Now est-il le meilleur moyen de mesurer les performances d'une fonction ?

Je dois trouver un goulot d'étranglement et mesurer le temps le plus précisément possible.

L'extrait de code suivant est-il le meilleur moyen de mesurer les performances ?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

0 votes

À propos, si vous ne cherchez pas quelque chose de rapide et sale, vous pouvez utiliser des compteurs de performance.

1 votes

Si vous avez besoin d'une plus grande précision, utilisez Stopwatch.GetTimestamp, sinon la réponse est bonne.

0 votes

@dbasnett Pouvez-vous donner plus de détails dans une réponse ?

664voto

Markus Olsson Points 12651

Non, ça ne l'est pas. Utilisez le Chronomètre (en System.Diagnostics )

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

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

Le chronomètre vérifie automatiquement l'existence de minuteries de haute précision.

Il convient de mentionner que DateTime.Now est souvent un peu plus lent que DateTime.UtcNow en raison du travail qui doit être fait avec les fuseaux horaires, DST et autres.

DateTime.UtcNow a typiquement une résolution de 15 ms. Voir Article de blog de John Chapman à propos de DateTime.Now précision pour un excellent résumé.

Fait intéressant : le chronomètre se replie sur DateTime.UtcNow si votre matériel ne supporte pas un compteur haute fréquence. Vous pouvez vérifier si Chronomètre utilise du matériel pour obtenir une haute précision en regardant le champ statique Chronomètre.estHauteRésolution .

3 votes

Je placerais un PerformWork() ; avant le Stopwatch pour "chauffer".

2 votes

Doit également ajouter la recommandation que si votre PerformWork() est très courte que vous pouvez l'appeler à plusieurs reprises et calculer la moyenne du lot d'appels. De même, chronométrez un lot entier d'appels plutôt que de démarrer/arrêter votre programme de recherche. Stopwatch pour éviter un effet stroboscopique qui brouillerait vos mesures de temps.

1 votes

Stopwatch n'est pas threadsafe sur multicore. Voir stackoverflow.com/questions/6664538/ y stackoverflow.com/questions/1149485/

94voto

Simucal Points 34961

Si vous voulez quelque chose de rapide et sale, je vous suggère d'utiliser plutôt Chronomètre pour un plus grand degré de précision.

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

Sinon, si vous avez besoin de quelque chose d'un peu plus sophistiqué, vous devriez probablement envisager d'utiliser un profileur tiers tel que ANTS .

60voto

Valentin Kuzub Points 4349

Cet article dit qu'il faut d'abord comparer trois alternatives, Stopwatch , DateTime.Now ET DateTime.UtcNow .

Il montre également que dans certains cas (lorsque le compteur de performance n'existe pas), le chronomètre utilise DateTime.UtcNow + un traitement supplémentaire. Pour cette raison, il est évident que dans ce cas DateTime.UtcNow est la meilleure option (parce que d'autres l'utilisent + un traitement).

Cependant, il s'avère que le compteur existe presque toujours - voir Explication sur le compteur de performance haute résolution et son existence par rapport au chronomètre .NET ? .

Voici un graphique de performance. Remarquez le faible coût de performance d'UtcNow par rapport aux alternatives :

Enter image description here

L'axe X est la taille des données de l'échantillon, et l'axe Y est le temps relatif de l'exemple.

Une chose. Stopwatch est meilleur est qu'il fournit des mesures de temps à plus haute résolution. Un autre avantage est sa nature plus OO. Cependant, la création d'une enveloppe OO autour de UtcNow ne peut pas être difficile.

1 votes

Le premier lien semble être cassé.

1 votes

La machine à remonter le temps peut le montrer, je suppose. En fait, pourquoi avez-vous édité "les trois", ce n'est pas nécessaire ici, je crois.

19voto

Anthony Mastrean Points 8582

Il est utile de pousser votre code d'évaluation dans une classe/méthode utilitaire. Le site StopWatch n'a pas besoin d'être Disposed ou Stopped sur erreur. Ainsi, le code le plus simple pour temps un peu de action es

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

Exemple de code d'appel

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

Voici la version de la méthode d'extension

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

Et un exemple de code d'appel

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat(“Did action in {0} ms.”, time);
}

1 votes

Pourquoi pas une meilleure granularité ? Beaucoup de choses se passent en moins d'une ms.

0 votes

Retournez la propriété Elapsed alors, c'est un TimeSpan. Je ne fais que vous montrer le modèle. Amusez-vous à le mettre en œuvre.

0 votes

Retourner à Elapsed.TotalMilliseconds pour une plus grande précision. Voir aussi cette question stackoverflow.com/questions/8894425/

17voto

jsight Points 16025

El chronomètre La fonctionnalité serait meilleure (plus grande précision). Je vous recommande également de télécharger l'un des profileurs les plus populaires ( DotTrace y ANTS sont ceux que j'ai le plus utilisés... la version d'essai gratuite de DotTrace est entièrement fonctionnelle et ne me harcèle pas comme certains autres).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X