2016-05-25 21 views
1

Es könnte ein Duplikat sein, aber ich wusste nicht, wie ich mein Problem erklären sollte.C# Stoppuhr - Inkonsistente Werte zurückgeben

Ich habe die Leistung Timing des Floyd Rivest Algorithmus Ich implementiert (in verschiedenen Fällen) mit der .NET Stoppuhr.

Um das Problem besser zu verstehen, hier ist der Code.

Ich Ausführung der 3 folgenden Verfahren nacheinander:

analysis.FRStopwatch (analysis.getOrderedArray()); analysis.FRStopwatch (analyse.getDescendingOrderedArray()); analysis.FRStopwatch (analysis.getUnorderedArray());

Verfahren FRStopwatch (int []) führt Folgendes aus:

public double FRStopwatch(int[] array) 
{ 
    frs = new FloydRivestSelection(array); 
    double avg = 0; 
    Stopwatch s = new Stopwatch(); 
    for (int i = 0; i < k.Length; i++) 
    { 
     Thread.Sleep(10); 
     s.Start(); 
     frs.Select(k[i]); 
     s.Stop(); 
     avg = avg + (double)s.Elapsed.TotalMilliseconds; 
     s.Reset(); 
     Console.WriteLine(avg); 
    } 
    avg = avg/(double)k.Length; 
    return avg; 
} 

Der Ausgang I erhalten, die folgt: Original Output

Wie man sehen kann, werden die Timing-Weg des geordneten Anordnung ist größer als die anderen.

Dann kommentierte I out der ersten Zeile gezeigt:

analysis.FRStopwatch (analysis.getOrderedArray());

und ausgeführt nur die verbleibenden zwei in der folgenden Reihenfolge:

analysis.FRStopwatch (analysis.getDescendingOrderedArray()); analysis.FRStopwatch (analysis.getUnorderedArray());

Ich habe die folgende Ausgabe: (oder die anderen beiden arbeiten nicht richtig) New Output Es scheint, wie die erste Methode, die die Stoppuhr verwendet funktioniert nicht richtig. Wie behebe ich, dass die Ergebnisse konsistent sind? Hat das Problem mit meinem Computer zu tun (CPU-Ticks usw.)?

+1

Wenn 'frs.Select (k [i]);' dauert weniger als ein paar Millisekunden, wird dies eine wirklich schreckliche Art sein, es zu Zeit. –

+1

@Kim Wenige Schlüsselwörter: Cache, JIT und möglicherweise Objektstatus. Weit gefehlt, um vollständig und perfekt zu sein (Sie müssen es immer noch cum grano salis verwenden, Eric Lippert hat einen netten Einstiegsbeitrag zum Thema Benchmarking geschrieben), aber Sie sollten versuchen, dieses [microbenchmark Dienstprogramm] (https: // github. com/arepti/NetMicroBenchmark) (Disclaimer: Ich habe es geschrieben) –

+1

Die anfängliche Verzögerung könnte auf JIT zurückzuführen sein - versuche, das Ganze zweimal in einer Schleife zu synchronisieren. –

Antwort

0

Ein einzelnes Beispiel einer kleinen Anfrage unterliegt zu vielen Variablen.

Um eine bessere Anzeige der Leistung zu erhalten, die jeweils ein paar tausend mal (etwa 6000) läuft, werfen dann die ersten 1000 oder so Ergebnisse von Warm-up Faktoren loszuwerden (JIT/Caching usw.).

Nehmen Sie Ihre Ergebnisse und teilen Sie durch 5000, um eine durchschnittliche Ausführungszeit zu erhalten. Dieser Ansatz hilft Ihnen, Ihre geistige Gesundheit zu bewahren und bessere Ergebnisse zu erzielen.

+0

Nachdem ich gelernt habe, dass es ein JIT-Problem ist, habe ich einen Weg gefunden, um dies mit Environment.TickCount zu umgehen. –

+0

@KimScicluna Wie Environment.TickCount wird Ihnen über JIT-Compiler helfen? Timer-Genauigkeit reduzieren? –

+0

Scratch das. Wie Sie bereits angedeutet haben, hat das Ausführen der Methode vor dem Test einfach den gewünschten Effekt. –

1

Diese Linien sind problematisch:

avg = avg + (double)s.Elapsed.TotalMilliseconds; 
Console.WriteLine(avg); 

Sie die durchschnittliche Erhöhung, aber Sie die Summe ausgegeben. Versuchen Sie stattdessen, den "aktuellen" Durchschnitt auszugeben.

avg = avg + (double)s.Elapsed.TotalMilliseconds; 
Console.WriteLine(avg/(i+1)); 

Oder diese, wenn Sie in den Laufzeiten jedes einzelnen Iteration Interesse:

Console.WriteLine(s.Elapsed.TotalMilliseconds); 
//reset after instead of before of course 
s.Reset(); 
+0

Nein, es ist nur eine schlecht benannte Variable. Wenn Sie nach der Schleife suchen, gibt es eine 'avg = avg/(double) k.Length;' -Anweisung, die den Durchschnitt berechnet. Die innere Variable hätte "Summe" heißen sollen. –

+0

@DStanley Genau. Es ist ** nach ** der Schleife. Der Rückgabewert ist korrekt, die Konsolenausgabe ist nicht –

0

Sie sind die akkumulative Summe der Zeiten auf der Konsole gedruckt wird, nicht der Durchschnitt noch die einzelnen Zeiten.

Ich schlage vor, dass Sie die einzelnen Zeiten wie dieser Druck:

s.Start(); 
frs.Select(k[i]); 
s.Stop(); 
var elapsed = (double)s.Elapsed.TotalMilliseconds; 
avg = avg + elapsed; //it is really sum, not avg 
s.Reset(); 
Console.WriteLine(elapsed); 

Ich denke, dass die Faust Iteration für das erste Verfahren wird die größte Menge an Zeit, wahrscheinlich wegen der JIT compilation verbrauchen. Wenn Sie einzelne Zeiten drucken, werden Sie dies deutlich sehen.

Außerdem schlage ich vor, Sie ändern den Variablennamen von avg zu sum, und berechnen nur den Durchschnitt nach der Schleife.