Frage

Ich muss einen Engpass finden und die Zeit so genau wie möglich messen.

Ist der folgende Codeausschnitt die beste Möglichkeit, die Leistung zu messen?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
War es hilfreich?

Lösung

Nein, ist es nicht.Benutzen Sie die Stoppuhr (In System.Diagnostics)

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

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

Die Stoppuhr prüft automatisch, ob hochpräzise Timer vorhanden sind.

Es lohnt sich das zu erwähnen DateTime.Now ist oft um einiges langsamer als DateTime.UtcNow aufgrund der Arbeit, die mit Zeitzonen erledigt werden muss, Sommerzeit und derartige.

DateTime.UtcNow hat normalerweise eine Auflösung von 15 ms.Sehen John Chapmans Blogbeitrag um DateTime.Now Präzision für eine tolle Zusammenfassung.

Interessante Kleinigkeiten:Die Stoppuhr fällt zurück DateTime.UtcNow wenn Ihre Hardware keinen Hochfrequenzzähler unterstützt.Sie können überprüfen, ob Stopwatch Hardware verwendet, um eine hohe Präzision zu erreichen, indem Sie sich das statische Feld ansehen Stopwatch.IsHighResolution.

Andere Tipps

Wenn Sie etwas Schnelles und Schmutziges wollen, würde ich für ein höheres Maß an Präzision stattdessen die Verwendung der Stoppuhr empfehlen.

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

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

Wenn Sie alternativ etwas Anspruchsvolleres benötigen, sollten Sie wahrscheinlich die Verwendung eines Profilers eines Drittanbieters in Betracht ziehen, z AMEISEN.

Dieser Artikel sagt, dass man zunächst drei Alternativen vergleichen muss, Stopwatch, DateTime.Now UND DateTime.UtcNow.

Es zeigt auch, dass Stopwatch in einigen Fällen (wenn kein Leistungsindikator vorhanden ist) DateTime.UtcNow + einige zusätzliche Verarbeitungsschritte verwendet.Aus diesem Grund ist es offensichtlich, dass DateTime.UtcNow in diesem Fall die beste Option ist (weil andere es verwenden + etwas Verarbeitung)

Wie sich jedoch herausstellt, existiert der Zähler fast immer – siehe Erklärung zum hochauflösenden Leistungsindikator und seiner Existenz im Zusammenhang mit der .NET-Stoppuhr?.

Hier ist ein Leistungsdiagramm.Beachten Sie, wie niedrig die Leistungskosten von UtcNow im Vergleich zu Alternativen sind:

Enter image description here

Die X-Achse ist die Größe der Beispieldaten und die Y-Achse ist die relative Zeit des Beispiels.

Eine Sache Stopwatch Der Vorteil besteht darin, dass es Zeitmessungen mit höherer Auflösung ermöglicht.Ein weiterer Grund ist seine eher OO-Natur.Erstellen Sie jedoch einen OO-Wrapper UtcNow kann nicht schwer sein.

Es ist nützlich, Ihren Benchmarking-Code in eine Dienstprogrammklasse/-methode zu übertragen.Der StopWatch Klasse muss nicht sein Disposed oder Stopped auf Fehler.Also der einfachste Code zu Zeit manche Aktion Ist

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

Beispiel-Aufrufcode

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

Hier ist die Version der Erweiterungsmethode

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

Und Beispiel-Aufrufcode

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

Der Stoppuhr Funktionalität wäre besser (höhere Präzision).Ich würde jedoch auch empfehlen, einfach einen der beliebten Profiler herunterzuladen (DotTrace Und AMEISEN sind die, die ich am häufigsten verwendet habe ...Die kostenlose Testversion von DotTrace ist voll funktionsfähig und stört nicht wie einige andere.

Verwenden Sie die Klasse System.Diagnostics.Stopwatch.

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

Das Gleiche gilt für die Stoppuhr, sie ist viel besser.

Hinsichtlich der Leistungsmessung sollten Sie auch prüfen, ob Ihr „// Some Execution Process“ ein sehr kurzer Prozess ist.

Bedenken Sie auch, dass die erste Ausführung Ihres „// Some Execution Process“ möglicherweise viel langsamer ist als nachfolgende Ausführungen.

Normalerweise teste ich eine Methode, indem ich sie 1.000 Mal oder 1.000.000 Mal in einer Schleife ausführe, und ich erhalte viel genauere Daten, als wenn ich sie einmal ausführe.

Dies sind alles großartige Möglichkeiten, die Zeit zu messen, aber das ist nur eine sehr indirekte Möglichkeit, Engpässe zu finden.

Der direkteste Weg, einen Engpass in einem Thread zu finden, besteht darin, ihn zum Laufen zu bringen und ihn mit einer Pause- oder Break-Taste anzuhalten, während er das tut, was Sie warten lässt.Tun Sie dies mehrmals.Wenn Ihr Engpass X % der Zeit in Anspruch nimmt, ist X % die Wahrscheinlichkeit, dass Sie ihn bei jedem Schnappschuss auf frischer Tat bemerken.

Hier finden Sie eine ausführlichere Erklärung, wie und warum es funktioniert

@Sean Chambers

Zu Ihrer Information: Die .NET-Timer-Klasse dient nicht der Diagnose, sie generiert Ereignisse in einem voreingestellten Intervall, wie folgt (von MSDN):

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

Das hilft Ihnen also nicht wirklich dabei, zu wissen, wie lange etwas gedauert hat, sondern nur, dass eine bestimmte Zeitspanne vergangen ist.

Der Timer wird auch als Steuerelement in System.Windows.Forms verfügbar gemacht ...Sie finden es in Ihrer Designer-Toolbox in VS05/VS08

Das ist der richtige Weg:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

Weitere Informationen finden Sie hier Verwenden Sie Stoppuhr anstelle von DataTime, um einen genauen Leistungszähler zu erhalten.

Visual Studio Team System verfügt über einige Funktionen, die bei diesem Problem hilfreich sein können.Im Wesentlichen können Sie Komponententests schreiben und diese in verschiedenen Szenarien kombinieren, um sie im Rahmen eines Stress- oder Auslastungstests für Ihre Software auszuführen.Dies kann dabei helfen, Codebereiche zu identifizieren, die sich am stärksten auf die Leistung Ihrer Anwendungen auswirken.

Die Microsoft-Gruppe „Patterns and Practices“ bietet einige Anleitungen dazu Anleitung zum Testen der Systemleistung von Visual Studio Team.

Ich habe gerade einen Beitrag in Vance Morrisons Blog darüber gefunden eine CodeTimer-Klasse Er schrieb, das macht die Verwendung StopWatch einfacher und macht nebenbei ein paar nette Sachen.

Ich habe diese Art der Leistungsüberprüfung nur sehr selten durchgeführt (ich neige dazu, einfach zu denken: „Das ist langsam, mach es schneller“), also habe ich mich fast immer dafür entschieden.

Bei Google werden viele Ressourcen/Artikel zur Leistungsprüfung angezeigt.

Viele erwähnen die Verwendung von Pinvoke, um Leistungsinformationen zu erhalten.In vielen Materialien, die ich studiere, wird nur die Verwendung von Perfmon erwähnt.

Bearbeiten:

Habe die Vorträge von StopWatch gesehen.Hübsch!Ich habe etwas gelernt :)

Das scheint ein guter Artikel zu sein

Die Art und Weise, wie ich in meinen Programmen verwende, ist die StopWatch-Klasse, wie hier gezeigt.

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

Das ist nicht professionell genug:

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

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

Eine zuverlässigere Version ist:

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

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

In meinem echten Code werde ich den GC.Collect-Aufruf hinzufügen, um den verwalteten Heap in einen bekannten Zustand zu versetzen, und den Sleep-Aufruf hinzufügen, damit verschiedene Codeintervalle im ETW-Profil einfach getrennt werden können.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top