PowerShell定时器/秒表精度

时间:2013-02-03 00:20:02

标签: powershell timer stopwatch

我发现即使在很短的时间内(即20秒),System.Diagnostics.Stopwatch类也具有可测量的不准确性。我的过程显示编码为运行20秒的进程的耗时20.3秒:

$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

在PowerShell中使用Stopwatch类时,这种准确性是否会出现偏差?它似乎与时间跨度不成比例地增加(即10秒关闭0.1和20比0.3)。我的代码有问题吗?

4 个答案:

答案 0 :(得分:19)

你有20秒暂停,但你还有其他事情发生。有一个循环可以递增并测试变量,并在每次迭代时写入经过的时间。这些额外的事情需要时间。

这仍然有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())"

答案 1 :(得分:2)

问题是,你想做什么?如果您要确定脚本运行需要多长时间,那么您应该使用秒表。但是,如果您尝试在指定的时间段后启动新的命令序列,请使用[System.Timers.Timer]并在计时器对象上注册已发生事件的事件。然后将注册事件的操作指定为您要完成的操作。

答案 2 :(得分:1)

秒表非常准确。睡眠不是。睡眠1秒钟通常会产生0.985s至1.015s的睡眠时间。但是,如果正在进行其他活动,则可能会更长。

答案 3 :(得分:0)

代码运行的总时间取决于其他因素,例如系统的繁忙程度。

查看.NET的源代码,我们可以看到[System.Diagnostics.Stopwatch]::StartNew()使用high resolution time计数器。它调用WINAPI QueryPerformanceCounter。那就是:该类非常精确!

我查看most recent source code of 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上的运行情况。

首先,我以正常优先级,低并发性运行了您的原始代码:Script took 20.14s

接下来,我运行原始代码,并执行其他一些CPU密集型过程:Tooks 24.21s

返回,我运行了我的代码版本,在空闲系统下没有写主机:Script tooks just 20.03s

最后一个与第一个有很大区别(空闲状态写入屏幕)。