2013-02-03 9 views
5

Ustalenie, że klasa System.Diagnostics.Stopwatch ma coś, co wydaje się mierzalnie niedokładne nawet w krótkim okresie czasu (tj. 20 sekund). Mój proces pokazujący czas, który upłynął od 20.3+ sekund dla procesu kodowanej do uruchomienia 20 sekundach:Powershell timer/stopwatch accuracy

$elapsed = [System.Diagnostics.Stopwatch]::StartNew() 
write-host "Started at $(get-date)" 
for ($t=1; $t -le 20; $t++) { 
    Write-Host "Elapsed Time: $($elapsed.Elapsed.ToString())" 
    sleep 1 
    } 
write-host "Ended at $(get-date)" 
write-host "Total Elapsed Time: $($elapsed.Elapsed.ToString())" 

    Started at 02/02/2013 15:08:43 
    Elapsed Time: 00:00:00.0329924 
    Elapsed Time: 00:00:01.0417435 
    Elapsed Time: 00:00:02.0547547 
    Elapsed Time: 00:00:03.0689716 
    Elapsed Time: 00:00:04.0820497 
    Elapsed Time: 00:00:05.0963413 
    Elapsed Time: 00:00:06.1113915 
    Elapsed Time: 00:00:07.1244044 
    Elapsed Time: 00:00:08.1396105 
    Elapsed Time: 00:00:09.1528952 
    Elapsed Time: 00:00:10.1659905 
    Elapsed Time: 00:00:11.1800884 
    Elapsed Time: 00:00:12.1940009 
    Elapsed Time: 00:00:13.2081824 
    Elapsed Time: 00:00:14.2223585 
    Elapsed Time: 00:00:15.2375023 
    Elapsed Time: 00:00:16.2506360 
    Elapsed Time: 00:00:17.2656845 
    Elapsed Time: 00:00:18.2790676 
    Elapsed Time: 00:00:19.2928700 
    Ended at 02/02/2013 15:09:04 
    Total Elapsed Time: 00:00:20.3080067 

Czy tego rodzaju dryf dokładności należy się spodziewać podczas korzystania z klasy stopera PowerShell? Wydaje się zwiększać nieproporcjonalnie do czasu (tj. 10 sekund jest wyłączone o 0,1 i 20 o 0,3). Czy mój kod jest wadliwy?

Odpowiedz

2

Chodzi o to, co chcesz zrobić ? Jeśli próbujesz ustalić, jak długo trwa uruchamianie skryptu, powinieneś użyć stopera. Jeśli jednak próbujesz uruchomić nową sekwencję poleceń po określonym czasie, użyj [System.Timers.Timer] i zarejestruj zdarzenie dla zdarzenia, które upłynęło w obiekcie timera. Następnie określ akcję zarejestrowanego zdarzenia, aby to, co próbujesz osiągnąć.

17

Masz 20 1 sekundę pauzy, ale ty też masz inne rzeczy. Istnieje pętla, która inkrementuje i testuje zmienną, a ty piszesz upływ czasu w każdej iteracji. Te dodatkowe rzeczy wymagają czasu.

ten wciąż ma 20 sekundową przerwę, a czas jaki upłynął jest bliżej do 20 sekund, ponieważ jest mniej dodatkowych rzeczy, które PowerShell ma robić:

$elapsed = [System.Diagnostics.Stopwatch]::StartNew() 
write-host "Started at $(get-date)" 
sleep 20 
write-host "Ended at $(get-date)" 
write-host "Total Elapsed Time: $($elapsed.Elapsed.ToString())" 
+2

Pozbądź się połączeń Started and Ended Write-Host i powinno być jeszcze bliżej. Stoper wykorzystuje system Windows z licznikiem wysokiej częstotliwości, więc jest dość dokładny. –

+0

Rynant, to byłoby 20 sekund. Ale to nie byłby już stoper - tylko czasomierz. To powstrzymałoby mój skrypt przed uruchomieniem do snu. Potrzebuję go, aby uruchomić proces i na koniec powiedzieć, ile czasu zajęło ukończenie. –

+0

Myślę, że przegapiłeś punkt mojego przykładu. Próbowałem pokazać, że klasa 'Diagnostics.Stopwatch' nie jest niedokładna. Powodem, dla którego stoper w twoim skrypcie pokazuje "20.3080067" sekund, jest to, że twój skrypt robi inne rzeczy poza snem. Powodem, dla którego wydaje się, że instrukcje "Get-Date" mają dokładnie 20 sekund, jest to, że wyświetlany czas jest zaokrąglany do najbliższej sekundy. – Rynant