Точност на таймера/хронометъра на PowerShell

Намирам, че класът System.Diagnostics.Stopwatch има нещо, което изглежда е измерима неточност, дори за кратък период от време (т.е. 20 секунди). Моят процес показва изминало време от 20,3+ секунди за процес, кодиран да изпълнява 20 секунди:

$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

Може ли да се очаква този вид отклонение на точността при използване на класа Stopwatch в PowerShell? Изглежда, че се увеличава непропорционално на времевия интервал (т.е. 10 секунди са отклонени с 0,1 и 20 с 0,3). Моят код ли е виновен?


person Local Needs    schedule 03.02.2013    source източник


Отговори (4)


Въпросът е какво се опитвате да направите? Ако се опитвате да определите колко точно време отнема изпълнението на скрипт, трябва да използвате хронометъра. Ако обаче се опитвате да стартирате нова последователност от команди след определен период, използвайте [System.Timers.Timer] и регистрирайте събитие за изтеклото събитие в обекта на таймера. След това задайте действието на регистрираното събитие спрямо това, което се опитвате да постигнете.

person Shaun    schedule 09.11.2013

Имате 20 паузи от 1 секунда, но имате и други неща, които се случват. Има цикъл, който увеличава и тества променлива и вие записвате изминалото време на всяка итерация. Тези допълнителни неща отнемат време.

Това все още има пауза от 20 секунди, а изминалото време е по-близо до 20 секунди, защото има по-малко допълнителни неща, които PowerShell трябва да направи:

$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())"
person Rynant    schedule 03.02.2013
comment
Отървете се от Started и Ended Write-Host calls и трябва да е още по-близо. Хронометърът използва API на високочестотния брояч на Windows, така че е доста точен. - person Keith Hill; 03.02.2013
comment
Rynant, това ще са 20 секунди. Но вече няма да е хронометър - просто таймер за заспиване. Това ще спре скрипта ми да работи, докато заспиването не завърши. Имам нужда от него, за да стартирам процес и накрая да ми кажете колко време отне да завърши. - person Local Needs; 08.02.2013
comment
Мисля, че пропусна смисъла на моя пример. Опитвах се да покажа, че класът Diagnostics.Stopwatch не е неточен. Причината, поради която хронометърът във вашия скрипт показва 20,3080067 секунди, е, че вашият скрипт прави и други неща, освен да спи. Освен това, причината, поради която операторите Get-Date изглеждат точно на 20 секунди, е, че показаното време е закръглено до най-близката секунда. - person Rynant; 08.02.2013
comment
Хванах те. И така, ако изпълнението на допълнителните ми команди извади StopWatch, как някой би използвал StopWatch, за да засече точно време на процес? Или StopWatch няма да е начинът да отидете за нещо подобно? Действителният ми код може да отнеме часове за завършване и бих искал да получа изминало време по-точно от това. - person Local Needs; 12.02.2013
comment
Изпълнението на допълнителни команди не изключва хронометъра. Изпълнението на допълнителни команди отнема повече време; следователно хронометърът показва точното време. Използвайте хронометър, точен е. - person Rynant; 12.02.2013

Хронометърът е много точен. Сънят не е. Сънят за 1 секунда обикновено ще доведе до сън от 0,985s до 1,015s; въпреки това може да бъде значително по-дълго, ако се извършват други дейности.

person David Berg    schedule 17.03.2020

Общото време на изпълнение на вашия код зависи от други фактори, като например колко натоварена е вашата система.

Разглеждайки изходния код на .NET, можем да видим, че [System.Diagnostics.Stopwatch]::StartNew() използва брояч за време с висока разделителна способност. Той извиква WINAPI QueryPerformanceCounter. Тоест: Класът е толкова прецизен!

Гледам най-новия изходен код на Start-Sleep и отбеляза, че той използва събития в режим на ядрото, за да внедри времето за изчакване. В допълнение към подробностите, които вече са споменати от потребителите, графикът на Windows може да постави други нишки, които да се изпълняват, когато powershel завърши изчакването ви за заспиване, което води до повече време, преди вашият код да изчисли изминалото време.

Освен това писането във видео е разходна операция, тъй като е много използван ресурс на компютъра. За да го заобиколя, пренаписвам кода ви, така че да не записва във видеото всеки път:

$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
write-host "Started at $(get-date)"

$out = new-object 'string[]' 100;

for ($t=1; $t -le 20; $t++) {
    $out[$t] = "Elapsed Time: $($elapsed.Elapsed.ToString())"
    sleep 1
}
$out;
write-host "Ended at $(get-date)"
write-host "Total Elapsed Time: $($elapsed.Elapsed.ToString())"

Разгледайте работата на система, powershell 5.1, работен плот, windows 10, CPU intel 3.0 Ghz.

Първо пуснах вашия оригинален код, с нормален приоритет, ниска едновременност: Скриптът отне 20,14 s

След това стартирах оригинален код с друг интензивен процес на процесора:Отнема 24,21 секунди

Обратно, изпълних моята версия на кода, без запис-хост при неактивна система:Скриптът отнема само 20,03 секунди

Последните имат голяма разлика с първите (неактивни с писане на екрана).

person Rodrigo    schedule 13.02.2020