6

System.Diagnostics.Stopwatch クラスには、短時間 (つまり 20 秒) であっても測定可能な不正確さがあるように思われることがわかりました。私のプロセスは、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

4 に答える 4

19

1 秒間の休止が 20 回ありますが、他のことも行っています。変数をインクリメントしてテストするループがあり、反復ごとに経過時間を書き込みます。これらの余分なものには時間がかかります。

これにはまだ 20 秒の一時停止があり、PowerShell が実行する必要のある余分な処理が少ないため、経過時間は 20 秒近くになります。

$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())"
于 2013-02-03T03:16:18.783 に答える
2

問題は、何をしようとしているのかということです。スクリプトの実行にかかる時間を正確に判断しようとしている場合は、ストップウォッチを使用する必要があります。ただし、指定した期間後に新しい一連のコマンドを開始しようとする場合は、[System.Timers.Timer] を使用して、timer オブジェクトに経過イベントのイベントを登録します。次に、登録されたイベントのアクションを、達成しようとしているものに指定します。

于 2013-11-09T04:35:07.373 に答える
1

ストップウォッチは非常に正確です。睡眠はそうではありません。通常、1 秒間スリープすると、0.985 秒から 1.015 秒のスリープになります。ただし、他の活動が進行中の場合は、大幅に長くなる可能性があります。

于 2020-03-17T06:52:24.950 に答える
0

コードの合計実行時間は、システムのビジー状態など、他の要因によって異なります。

.NET のソース コードを見ると、[System.Diagnostics.Stopwatch]::StartNew()高解像度の時間カウンターを使用していることがわかります。WINAPI QueryPerformanceCounterを呼び出します。つまり、クラスは非常に正確です。

Start-Sleep の最新のソース コードを調べたところ、カーネル モード イベントを使用して時間待機が実装されていることがわかりました。ユーザーによって既に言及されている詳細に加えて、Windows スケジュールは、powershell がスリープ時間の待機を終了したときに別のスレッドを実行するように設定できるため、コードが経過時間を計算するまでにより多くの時間がかかります。

また、ビデオへの書き込みは、コンピューターのリソースを非常に多く使用するため、コストのかかる操作です。それを回避するために、コードを書き直して、毎回ビデオに書き込まないようにします。

$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 秒かかりました

次に、CPU を集中的に使用する別のプロセスを使用して、元のコードを実行しました。24.21 秒かかりました

戻って、アイドル状態のシステムで write-host なしでコードのバージョンを実行しました:スクリプトはわずか 20.03 秒かかりました

最後のものは、最初のものとは大きな違いがあります (画面への書き込みでアイドル状態)。

于 2020-02-13T02:17:27.253 に答える