Ile trwa Sleep(1ms)?

Witam,

Ile trwa "System.Threading.Thread.Sleep(1);"?

Ostatnio przeprowadziłem test w którym chciałem sprawdzić możliwości Windows jako systemu czasu rzeczywistego, czyli postanowiłem sprawdzić ile zajmie uśpienie systemu na 1 ms.

Test wyglądał następująco:

    //wlasciwy test
    MinMaxAvg minmaxavg = new MinMaxAvg();
    for (int test = 0; test < 10; test++)
    {
        for (int i = 0; i < test; i++) 
          System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ThreadProc));
        MinMaxAvg minmaxavg_local = new MinMaxAvg();
        for (int i = 0; i < 1000; i++)
        {
            System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
            System.Threading.Thread.Sleep(1);
            sw.Stop();
            double time_in_milis = (double)sw.Elapsed.Ticks / (double)TimeSpan.TicksPerMillisecond;
            minmaxavg.AddValue(time_in_milis);
            minmaxavg_local.AddValue(time_in_milis);
        }
        Console.WriteLine(String.Format("test #{0}: {1}",test,minmaxavg.ToString()));
    }
    Console.WriteLine("Summary: "+minmaxavg.ToString());

Gdzie MinMaxAvg to klasa wyznaczająca minimum, maksimum i średnią, a dodatkowe wątki uruchamiane w puli, to ciężka praca do wykonania w postaci:

long val = 0; for (int i = 0; i < 200000000 ; i++)val += i;

Cały kod dostępny tutaj: http://www.mm.pl/~maciekz/download/sleep1test.zip

Wyniki:

Procesor: Liczba procesorów: 1
Liczba rdzeni: 2
Typ: Intel64 Family 6 Model 23 Stepping 10
Taktowanie: 2534Mhz

test #0: Minimum=0,1977; Average=0,9902776; Maximum=1,4756;
test #1: Minimum=0,1977; Average=0,991854700000001; Maximum=1,6275;
test #2: Minimum=0,1977; Average=0,993487600000001; Maximum=2,7511;
test #3: Minimum=0,0628; Average=1,041576725; Maximum=191,6798;
test #4: Minimum=0,0546; Average=1,07218284; Maximum=197,0183;
test #5: Minimum=0,0546; Average=1,05993491666667; Maximum=197,0183;
test #6: Minimum=0,0546; Average=1,05101061428572; Maximum=197,0183;
test #7: Minimum=0,0546; Average=1,04429911250001; Maximum=197,0183;
test #8: Minimum=0,0546; Average=1,03930382222223; Maximum=197,0183;
test #9: Minimum=0,0546; Average=1,03537345000001; Maximum=197,0183;
Summary: Minimum=0,0546; Average=1,03537345000001; Maximum=197,0183;

oraz na innym komputerze:

Procesor: Liczba procesorów: 1
Liczba rdzeni: 2
Typ: x86 Family 15 Model 4 Stepping 7
Taktowanie: 2824Mhz

test #0: Minimum=0,3589; Average=1,9402355; Maximum=2,8757;
test #1: Minimum=0,3589; Average=1,9407492; Maximum=2,8757;
test #2: Minimum=0,3589; Average=1,9629437; Maximum=36,8966;
test #3: Minimum=0,3589; Average=1,977586025; Maximum=38,9287;
test #4: Minimum=0,3589; Average=1,9903297; Maximum=38,9287;
test #5: Minimum=0,3589; Average=2,01788521666667; Maximum=42,7573;
test #6: Minimum=0,3589; Average=2,05227467142857; Maximum=46,8195;
test #7: Minimum=0,3589; Average=2,0842682375; Maximum=60,2805;
test #8: Minimum=0,1684; Average=2,11843057777778; Maximum=62,2691;
test #9: Minimum=0,1684; Average=2,13040769; Maximum=62,5606;
Summary: Minimum=0,1684; Average=2,13040769; Maximum=62,5606;

Czyli usypiając nasz wątek na 1 ms, to średnio czekamy 1 - 2 ms, ale może się zdarzyć, że będziemy spać dużo krócej (nawet 55 mikrosekund) lub dużo dłużej ponad 200 milisekund (200 razy dłużej niż zamierzaliśmy)

A ile u was trwa Sleep(1)??

A może to efekt złego testu/pomiaru??

Pewnie to kwestia szeregowania procesów w Windows i jak ten zadanie wyszereguje to ponowne zaszeregowanie musi trwać. A może ktoś ma inne lepsze wytłumaczenie?

A może to kwestia platformy .NET??

Robił ktoś podobne testy w innych językach? (c++ , java?)

Pozdrawiam,

Maciek

http://maciej-progtech.blogspot.com/

  • Thread.Sleep to tylko polecenie by wątek spał przez minimum pewien czas.

    Czyli wydajesz wątkowi polecenie "śpij 1 ms", wątek jest przenoszony do stanu uśpionego, który w .NET nazywa się WaitSleepJoin, po minięciu tej 1 ms [około] wątek jest przesuwany do stanu aktywnego, ale to sheduler decyduje kiedy ten wątek zostanie uruchomiony. W pewnych warunkach możesz czekać nawet bardzo długo jeżeli system uzna, że są wątki które są ważniejsze.

  • Ja chciałbym dodać, że procesor tak na prawdę nie jest wielowątkowy - czyli nie wykonuje kilku rzeczy na raz. Od tego są przerwania, by symulować robienie kilku rzeczy w jednym momencie. Między kwantami czasu pracy procesora, które są przydzielane procesom są jeszcze przerwania, które zmieniają te procesy. Każdy program ma przydzielone kolejne kwanty czasu dostępu do procesora, więc jeśli kwant czasu przydzielony procesowi nie pokrywa się z czasem obudzenia procesu to czas będzie bardziej lub mniej odbiegał od oczekiwanego czasu. Samo odczytanie czasu też może się drastycznie (przy tej dokładności) różnić od faktycznej różnicy czasu.

    Przyznam się szczerze, ze nie wiem jak to jest faktycznie zrobione, ale ja bym odjął trochę czasu, który jest potrzebny na sprawdzenie aktualnego czasu, nie byłoby to idealne rozwiązanie, ale byłoby trochę bliżej prawdy.

    Mój komputer zazwyczaj drukuje 0.004 s więcej czasu niż wydam polecenie (mierzyłem od 1 sekundy wzwyż), chociaż zdarzają się odstępstwa (nie przypominam sobie jednak, by wynik był krótszy niż ja tego chciałem). Dokładniejszych pomiarów nie robiłem bo mi nie były potrzebne. Wychodzę z założenia, ze zamiast czekać 1000 razy 1 milisekundę można przecież poczekać jedną sekundę, zaokrąglenie będzie występowało jednokrotnie więc bardziej przybliżony wynik, z resztą człowiek nie zauważy różnicy, a procesy produkcyjne chyba mogą sobie pozwolić na milisekundowe różnice.

    BTW. Znowu to "programowanie" w tagach ;)

  • C++ sprawdzałem, tak małe czasy raczej trudno osiągnąć, osobiście widziałem różnicę w działaniu programu przy Sleep(10) - mogę coś zaraz naskrobać w Visual C++ i podać 'aktualne' wyniki ;-)

  • Jeżeli ten Sleep() działa tak jak myślę, że działa - czyli opiera się o systemowe funkcje uśpienia wątku, to mogę podać pewne wytłumaczenie występowania różnic, jednak nie umiem wyjaśnić w tym momencie skąd tak krótkie czasy dostałeś.

    Reguła usypiania klasycznego jest taka, że należy odczekać przynajmniej czas podany w argumencie wywołania uśpienia wątku, przed przywróceniem do puli oczekujących na wykonanie; w teorii oznacza to, że nasz czas zawszę będzie odrobinę dłuższy od zadanego, zależny od poziomu obciążenia. W systemach stosuje się pewne sztuczki, polegające na estymacji czasu potrzebnego na przywrócenie wątku do puli oczekujących na wykonanie i o tyle pomniejsza się czas użytkownika.

    Trochę inaczej sprawa się na z uśpieniami w jądrze systemu - wyróżniamy dwa rodzaje: długotrwałe i precyzyjne uśpienie. To pierwsze jest podobne do opisanego powyżej, z tą różnicą, że pod koniec okresu oczekiwania wprowadza się minimalne uśpienie precyzyjne.

    Uśpienie precyzyjne polega na wykonaniu określonej niewielkiej ilości rozkazów nop, co przy znanej częstotliwości zegara pozwala precyzyjnie z dokładnością do części nanosekundy trafić z czasem.

Zaloguj się, aby dodać swoją odpowiedź