6
votes

PowerShell minuterie / précision de chronomètre

Je trouve que le système.diagnostics.stopwatch Classe a ce qui semble être une inexactitude mesurable, même sur une courte période (c'est-à-dire 20 secondes). Mon processus montre une heure écoulée de 20,3 secondes pour un processus codé pour exécuter 20 secondes:

$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


0 commentaires

4 Réponses :


19
votes

Vous avez 20 pauses de 1 seconde, mais vous avez d'autres choses qui se passent aussi. Il existe une boucle qui augmente et teste une variable et vous écrivez le temps écoulé sur chaque itération. Ces choses supplémentaires prennent du temps.

Cela a toujours une pause de 20 secondes, et le temps écoulé est plus proche de 20 secondes car il y a moins de choses supplémentaires que PowerShell doit faire: P>

$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())"


5 commentaires

Débarrassez-vous des appels d'hôte écriture démarrés et terminés et cela devrait être encore plus proche. Chronomètre utilise l'API de compteur haute fréquence de Windows 'afin qu'il soit assez précis.


Rynant, ce serait 20 secondes. Mais ce ne serait plus un chronomètre - juste une minuterie de sommeil. Cela empêcherait mon script de courir jusqu'à ce que le sommeil soit terminé. J'en ai besoin pour courir un processus et à la fin, dites-moi combien de temps il a fallu pour compléter.


Je pense que vous avez manqué le point de mon exemple. J'essayais de montrer que la classe diagnostics.stopwatch n'est pas inexacte. La raison pour laquelle le chronomètre de votre script affiche "20.3080067" Seconds est parce que votre script fait d'autres choses en plus de dormir. En outre, la raison pour laquelle les instructions get-date semblent être exactement à 20 secondes d'être car l'heure affichée est arrondie à la seconde la plus proche.


Je t'ai eu. Donc, si vous exécutez mes commandes supplémentaires lève les chronomètres, comment utiliser une chronomètre pour effectivement un processus avec précision? Ou chronométrant ne serait-il pas la voie à suivre pour quelque chose comme ça? Mon code actuel pourrait prendre des heures à compléter et je voudrais obtenir un temps écoulé plus précis que cela.


Exécuter des commandes supplémentaires ne jette pas les chronomètres. Exécuter des commandes supplémentaires prend plus de temps; Par conséquent, chronomètre montre la bonne heure. Utilisez chronomètre, il est précis.



2
votes

La question est, qu'essayez-vous de faire? Si vous essayez de déterminer combien de temps il faut un script à exécuter, vous devez utiliser exactement le chronomètre. Toutefois, si vous essayez de démarrer une nouvelle séquence de commandes après une période spécifiée, utilisez un [System.Timers.Timer] et enregistrez un événement pour l'événement écoulé sur l'objet TIMER. Spécifiez ensuite l'action de l'événement enregistré à ce que vous essayez d'accomplir.


0 commentaires

0
votes

Le temps total de votre code est exécuté, dépend d'autres facteurs, tels que la fréquentation de votre système.

En regardant le code source de .NET, nous pouvons voir que [System.Diagnostics.stopwatch] :: StartNew () Utilise le temps haute résolution compteur. Il appelle le Winapi QueryPerformEcanceCounter < / a>. C'est-à-dire que la classe est si précise!

Je regarde Code source le plus récent de Start-Sleep et a noté qu'il utilise des événements en mode noyau pour mettre en œuvre le temps d'attente. En plus des détails déjà mentionnés par les utilisateurs, la planification de Windows peut mettre un autre thread à exécuter lorsque PowerShel termine votre attente pour le temps de veille, ce qui a entraîné plus de temps avant que votre code ne calcule le temps écoulé.

aussi, écrivant à la La vidéo est une opération de coût car il s'agit d'une ressource très haute utilisée sur ordinateur. Pour réussir, je réécris votre code, de sorte que cela n'écrit pas à la vidéo à chaque fois: xxx

Jetez un coup d'oeil sur les exécutions sur système, PowerShell 5.1, bureau, Windows 10, CPU Intel 3.0 GHz.

Premier, j'ai couru votre code d'origine, à la priorité normale, faible simultanéité: script a pris 20.14s

Suivant, j'ai dirigé le code d'origine, avec un autre processus intensif de la CPU: a pris 24,21s

retour, j'ai exécuté ma version de code, sans l'hôte en écriture sous système de veille: Script n'a pris que 20.03s

Le dernier a une grande différence pour la première ( oisif avec écrit à l'écran).


0 commentaires

1
votes

chronomètre est très précis. Le sommeil n'est pas. Dormir pendant 1 seconde donnera typiquement n'importe où de 0,985 à un sommeil 1.015S; Cependant, cela pourrait être sensiblement plus long s'il existe d'autres activités.


0 commentaires