Oblicz czas wykonania metody

533

Możliwa duplikat:
Jak zmierzyć czas działania funkcji?

Mam metodę zajmującą czas we / wy, która kopiuje dane z lokalizacji do innej. Jaki jest najlepszy i najbardziej realny sposób obliczania czasu wykonania? Thread? Timer? Stopwatch? Jakieś inne rozwiązanie? Chcę najbardziej dokładny i najkrócej jak to możliwe.

Mahdi Tahsildari
źródło

Odpowiedzi:

1129

Stopwatch jest przeznaczony do tego celu i jest jednym z najlepszych sposobów pomiaru czasu wykonania w .NET.

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

Nie należy używać funkcji DateTime do mierzenia czasu wykonania w .NET.


AKTUALIZACJA:

Jak wskazał @ series0ne w sekcji komentarzy: Jeśli chcesz naprawdę dokładnego pomiaru wykonania jakiegoś kodu, będziesz musiał użyć liczników wydajności wbudowanych w system operacyjny. Następujące odpowiedź zawiera piękny przegląd.

Darin Dimitrov
źródło
2
Dokładnie, a co z tym przypadkiem: mam pętlę Foreach, która ma ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); wnętrze, ale stoper zatrzymuje się, zanim wszystko zostanie zrobione.
Mahdi Tahsildari,
13
@DarinDimitrov - Stoper nie jest całkowicie dokładny? pamiętaj, że szum w tle .NET (taki jak JIT) powoduje różne czasy wykonania. Dlatego realistycznie, aby uzyskać dokładne pomiary, PO powinien używać profilera wydajności.
Matthew Layton
3
@ series0ne, bardzo dobry punkt. Zaktualizuję moją odpowiedź, aby uwzględnić Twój cenny komentarz.
Darin Dimitrov
7
@DarinDimitrov, niedawno miałem wywiad z bardzo wykwalifikowanym starszym programistą. Wskazał mi, że używanie DateTimes jest w rzeczywistości dokładniejsze niż używanie StopWatch. Powiedział, że powodem tego jest to, że Stoper w .NET nie bierze pod uwagę powinowactwa procesora, a zatem, jeśli twój wątek przechodzi z jednego rdzenia do drugiego, StopWatch nie bierze pod uwagę czasu wykonania w innych rdzeniach; tylko ten, w którym wątek rozpoczął wykonywanie. Jaka jest twoja opinia na ten temat?
Matthew Layton
2
@ series0ne, to, co starszy programista powiedział ci o Stoper i DateTime, jest absolutną prawdą. Tyle że z DateTime nie masz wystarczającej dokładności. Problem polega na tym, że w .NET nie ma takiej klasy, która pozwalałaby na wszystkie te funkcje.
Darin Dimitrov
75

Z własnego doświadczenia, System.Diagnostics.Stopwatchklasa może być wykorzystana do pomiaru czasu wykonania metody, jednak UWAGA : nie jest całkowicie dokładna!

Rozważ następujący przykład:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

Przykładowe wyniki

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

Teraz się zastanawiasz; „no cóż, dlaczego za pierwszym razem zajęło to 132 ms, a przez resztę znacznie mniej czasu?”

Odpowiedź jest taka, Stopwatchże nie kompensuje aktywności „szumu tła” w .NET, takiej jak JITing. Dlatego przy pierwszym uruchomieniu tej metody .NET JIT jest pierwszy. Czas potrzebny na to jest dodawany do czasu wykonania. Podobnie inne czynniki będą również powodować zmianę czasu wykonania.

To, czego naprawdę powinieneś szukać absolutnej dokładności, to profilowanie wydajności !

Spójrz na następujące:

RedGate ANTS Performance Profiler jest produktem komercyjnym, ale zapewnia bardzo dokładne wyniki. - Zwiększ wydajność swoich aplikacji dzięki profilowaniu .NET

Oto artykuł StackOverflow na temat profilowania: - Jakie są dobre profile .NET?

Napisałem również artykuł na temat profilowania wydajności za pomocą stopera, na który warto spojrzeć - profilowanie wydajności w .NET

Matthew Layton
źródło
2
@mahditahsildari Nie ma problemu. Cieszę się, że mogłem pomóc! :-)
Matthew Layton
41
Nie jestem pewien, dlaczego jest to przykład niedokładności . Stoper dokładnie mierzy całkowity koszt pierwszego połączenia, co z pewnością jest istotne dla klienta, który będzie korzystał z tego kodu. Nie dbają o to, czy te 132 milisekundy obciążają wykonanie metody, czy o fluktuacje, dbają o całkowity czas, który upłynął.
Eric Lippert,
2
@ series0ne Jeśli zależy Ci na wydajności pętli, zmierz jej wydajność. Nie zakładaj po prostu, że zrobienie czegoś n razy oznacza, że ​​będzie dokładnie n razy wolniejsze niż wykonanie go raz.
svick,
3
Po pierwsze, próbka kodu powinna generować wynik o stale rosnącej liczbie, ponieważ StopWatch nigdy nie jest resetowany w pętli. I przez „powinienem” rozumiem, że tak (sprawdziłem). Twoje dane wyjściowe nie są zgodne z kodem. Po drugie, kiedy poprawiłem kod, aby wykonać Stop / Write / Reset / Start w pętli, pierwszy pomiar był taki sam jak reszta. Domyślam się, że Twój DoSomething robi coś dłużej przy pierwszym uruchomieniu. Przyczyną może być JIT, ale nie dlatego, że Stoper wpływa na pomiar. Stąd -1.
ILIA BROUDNO
2
ILIA BROUDNO ma absolutną rację, mam takie same wyniki. @ series0ne, masz Console.WriteLine wewnątrz pętli, pisząc jak dotąd ms; ponieważ zegarek zatrzymujesz dopiero PO zakończeniu pętli, rośnie z upływem czasu z każdą iteracją, więc powinniśmy zobaczyć coś w rodzaju 3, 6, 10, 12, 15 ... wraz z upływem czasu po wykonaniu.
Rui Miguel Pinheiro
29

StopWatch klasa szuka najlepszego rozwiązania.

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

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

Ma również pole statyczne o nazwie Stopwatch.IsHighResolution. Oczywiście jest to problem ze sprzętem i systemem operacyjnym.

Wskazuje, czy licznik czasu jest oparty na liczniku wydajności o wysokiej rozdzielczości.

Soner Gönül
źródło
18

Jeśli chcesz zrozumieć wydajność, najlepszą odpowiedzią jest skorzystanie z profilera.

W przeciwnym razie System.Diagnostics.StopWatch zapewnia zegar o wysokiej rozdzielczości.

Jeff Foster
źródło
Absolutnie poprawne! Jestem trochę zawiedziony, że tak wielu tutaj sugerowało użycie Stoper, ponieważ nie jest to całkowicie dokładne. Jednak, jak zasugerowałeś użycie profilera wydajności, jest to właściwy sposób, aby to zrobić! +1
Matthew Layton
7

StopWatch użyje licznika o wysokiej rozdzielczości

Stoper mierzy upływ czasu, zliczając tyknięcia zegara w leżącym u jego podstaw mechanizmie zegara. Jeśli zainstalowany sprzęt i system operacyjny obsługują licznik wydajności wysokiej rozdzielczości, klasa Stopwatch używa tego licznika do pomiaru upływającego czasu. W przeciwnym razie klasa Stopwatch używa czasomierza systemowego do pomiaru upływającego czasu. Użyj pól Częstotliwość i IsHighResolution, aby określić precyzję i rozdzielczość implementacji taktowania stopera.

Jeśli mierzysz IO, twoje dane prawdopodobnie będą miały wpływ na zdarzenia zewnętrzne i bardzo bym się martwił. dokładność (jak wskazano powyżej). Zamiast tego wziąłbym zakres pomiarów i wziął pod uwagę średnią i rozkład tych liczb.

Brian Agnew
źródło
0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
Md.Rakibuz Sultan
źródło