2010-10-11 23 views
36

Chcę zmierzyć wykonanie fragmentu kodu i zastanawiam się, jaka jest najlepsza metoda to zrobić?Zmierz czas wykonywania w C#

Opcja 1:

DateTime StartTime = DateTime.Now; 

//Code 

TimeSpan ts = DateTime.Now.Subtract(StartTime); 
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
Console.WriteLine(elapsedTime, "RunTime"); 

Opcja 2: pomocą System.Diagnostics;

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

    //Code 

    stopWatch.Stop(); 
    // Get the elapsed time as a TimeSpan value. 
    TimeSpan ts = stopWatch.Elapsed; 

    // Format and display the TimeSpan value. 
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
    Console.WriteLine(elapsedTime, "RunTime"); 

Nie jest to po prostu analiza porównawcza, która jest częścią aplikacji. Czas potrzebny do wykonania funkcji to odpowiednie dane. Nie musi to być jednak atomowa ani hiper-dokładna.

Która opcja jest lepsza dla kodu produkcyjnego, czy ktoś inny używa czegoś innego i być może lepszego?

+0

Dobre pytanie! Jestem ciekawy co do odpowiedzi! –

Odpowiedz

28

Klasa Stopwatch został zaprojektowany specjalnie do pomiaru upływu czasu i może (jeśli są dostępne na sprzęcie) zapewniają dobrą ziarnistość/dokładność przy użyciu bazowego zegara sprzętowego o wysokiej częstotliwości. Wydaje się, że to najlepszy wybór.

Za pomocą IsHighResolution property można określić, czy dostępny jest tryb wysokiej rozdzielczości. Per dokumentacji, ta klasa oferuje opakowania na „najlepszych dostępnych” API Win32 do dokładnego harmonogramu:

Konkretnie, Frequency pola i GetTimestamp metoda może być stosowana w zamiast niezarządzani Win32 API QueryPerformanceFrequency i QueryPerformanceCounter.

Istnieje szczegółowe tło dla tych interfejsów API Win32 [tutaj] oraz w połączonych dokumentach MSDN 2.

wysokiej rozdzielczości timera

Licznik jest ogólnym terminem używanym w programowaniu odwołać się do zmiennej zwiększany . Niektóre systemy zawierają licznik wydajności o wysokiej rozdzielczości , który zapewnia wysoką rozdzielczość czasu, który upłynął.

Jeżeli wysokiej rozdzielczości wydajność licznik istnieje w systemie, można użyć funkcji QueryPerformanceFrequency wyrazić częstotliwość, w impulsów na sekundę. Wartość liczby zależy od procesora. Na niektórych procesorach może być na przykład liczba cykli zegara procesora .

The QueryPerformanceCounter funkcji odczytuje bieżącą wartość licznika wydajności wysokiej rozdzielczości. Wywołanie tej funkcji na początku i końca odcinka o kodzie powoduje, że aplikacja zasadniczo używa licznika jako licznika czasu wysokiej rozdzielczości . Załóżmy na przykład, że QueryPerformanceFrequency oznacza, że ​​częstotliwość licznika wydajności wysokiej rozdzielczości wynosi 50 000 zliczeń na sekundę. Jeśli aplikacja wzywa QueryPerformanceCounter natychmiast przed i bezpośrednio po sekcji kodu być czasowe, wartości licznik może być 1500 i 3500 liczy liczy, odpowiednio. Te wartości wskazują, że 0,04 sekundy upłynęło (2000 zliczeń) podczas wykonywania kodu .

+0

'Stoper' również korzysta z timera wysokiej rozdzielczości (gdy jest dostępny), co jest niezbędne podczas pomiaru kodu z krótkimi czasami realizacji. – Justin

+0

@Kragen - o to mi chodziło o zegar. Wyjaśnię, odwołując się do interfejsów API Win32. –

+0

Należy pamiętać, że jest to "Stoper", a nie "StopWatch" (drobne, wiem, ale autoreplikacje zależności nie zadziałają, jeśli źle się z tym zgadzasz). –

5

Żadne nie zaszkodzi wydajności, ponieważ mówisz, że to nie jest tak ważne. StopWatch wydaje się bardziej odpowiedni - odejmujesz tylko czas, a nie datę od innej. Danych zajmuje nieco więcej pamięci i czasu procesora, aby sobie poradzić. Istnieją również sposoby na uproszczenie kodu w przypadku, gdy planujesz ponowne użycie go w kilku miejscach. Przeciążenie using przychodzi na myśl. Poszukuję przykładu. Ok, kod skradzione:

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable 
{ 
    private readonly Stopwatch _stopWatch; 

    public ConsoleAutoStopWatch() 
    { 
     _stopWatch = new Stopwatch(); 
     _stopWatch.Start(); 
    } 

    public void Dispose() 
    { 
     _stopWatch.Stop(); 
     TimeSpan ts = _stopWatch.Elapsed; 

     string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
              ts.Hours, ts.Minutes, ts.Seconds, 
              ts.Milliseconds/10); 
     Console.WriteLine(elapsedTime, "RunTime"); 
    } 
} 

private static void UsingStopWatchUsage() 
{ 
    Console.WriteLine("ConsoleAutoStopWatch Used: "); 
    using (new ConsoleAutoStopWatch()) 
    { 
     Thread.Sleep(3000); 
    } 
} 
+0

Nie wydaje mi się, żeby zajęło to więcej czasu. Myślę, że jest to mniej dokładne, ponieważ nie jest ono przeznaczone do tego rodzaju pomiarów. – codekaizen

6

ja zazwyczaj używają StopWatch do tego rodzaju sytuacji.

Od MSDN strony:

StopWatch

zapewnia zestaw metod i właściwości, które można użyć do dokładnie zmierzyć czas, który upłynął.

W następnym poście używam go porównać czas realizacji LINQ vs PLINQ:

Parallel LINQ (PLINQ) with Visual Studio 2010

+0

+1 dla łącza do MSDN, gdzie znalazłem, że wygląda na to, że nazwa została zmieniona z 'StopWatch' na' Stopwatch' –

1

Obie będą najprawdopodobniej pasować do Twoich potrzeb, ale powiedziałbym, że użyję StopWatch. Czemu? Bo to jest przeznaczone dla zadania, które wykonujesz.

Masz jedną klasę, która została zbudowana, aby zwracać aktualną datę/czas, która, jak to się dzieje, może być używana do mierzenia czasu, a masz jedną klasę zaprojektowaną specjalnie do synchronizowania rzeczy.

W tym przypadku różnice istnieją tylko wtedy, gdy potrzebna jest dokładność milisekundowa (w takim przypadku StopWatch jest dokładniejsza), ale jako ogólną zasadę, jeśli narzędzie istnieje specjalnie dla zadania, którego szukasz, jest ono lepsze używać.

13

To nie tylko, że StopWatch jest dokładniejsza, ale także, że DateTime.Now da niepoprawne wyniki w pewnych okolicznościach.

Zastanów się, co dzieje się podczas czasu letniego przełączania, np — wykorzystaniem DateTime.Now może faktycznie dać negatywny odpowiedź!

1

Mam małą klasę do zrobienia tego typu rzeczy ad hoc.Używa klasy stoper - c# micro perfomance testing.

np.

var tester = new PerformanceTester(() => SomeMethod()); 
tester.MeasureExecTime(1000); 
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds)); 
0

skorzystać z poniższego kodu

DateTime dExecutionTime; 
dExecutionTime = DateTime.Now; 
     TimeSpan span = DateTime.Now.Subtract(dExecutionTime); 
        lblExecutinTime.Text = "total time taken " + Math.Round(span.TotalMinutes,2) + " minutes . >>---> " + DateTime.Now.ToShortTimeString(); 
0

Wziąłem odpowiedź Hamish jest uproszczona go i sprawiły, że nieco bardziej ogólnie w przypadku trzeba zalogować się gdzie indziej:

public class AutoStopWatch : Stopwatch, IDisposable { 

    public AutoStopWatch() { 
     Start(); 
    } 

    public virtual void Dispose() { 
     Stop(); 
    } 
} 

public class AutoStopWatchConsole : AutoStopWatch { 

    private readonly string prefix; 

    public AutoStopWatchConsole(string prefix = "") { 
     this.prefix = prefix; 
    } 

    public override void Dispose() { 
     base.Dispose(); 

     string format = Elapsed.Days > 0 ? "{0} days " : ""; 
     format += "{1:00}:{2:00}:{3:00}.{4:00}"; 

     Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds/10)); 
    } 
} 

private static void Usage() { 

    Console.WriteLine("AutoStopWatch Used: "); 
    using (var sw = new AutoStopWatch()) { 
     Thread.Sleep(3000); 

     Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'")); 
    } 

    Console.WriteLine("AutoStopWatchConsole Used: "); 
    using (var sw = new AutoStopWatchConsole()) { 
     Thread.Sleep(3000); 
    } 

}