Czas wykonywania polecenia w PowerShell


217

Czy istnieje prosty sposób na czas wykonania polecenia w programie PowerShell, taki jak polecenie „time” w systemie Linux?
Wymyśliłem to:

$s=Get-Date; .\do_something.ps1 ; $e=Get-Date; ($e - $s).TotalSeconds

Ale chciałbym coś prostszego

time .\do_something.ps1

Odpowiedzi:


337

Tak.

Measure-Command { .\do_something.ps1 }

Zauważ, że jednym niewielkim minusem Measure-Commandjest to, że nie widzisz żadnych stdoutwyników.

[Aktualizacja, dzięki @JasonMArcher] Możesz to naprawić, przesyłając dane wyjściowe polecenia do jakiegoś polecenia, które zapisuje na hoście, np Out-Default. Staje się:

Measure-Command { .\do_something.ps1 | Out-Default }

Innym sposobem na sprawdzenie wyniku byłoby użycie Stopwatchklasy .NET w następujący sposób:

$sw = [Diagnostics.Stopwatch]::StartNew()
.\do_something.ps1
$sw.Stop()
$sw.Elapsed

114
Możesz także zobaczyć takie dane wyjściowe, Measure-Command {ps | Out-Default}. Lub cokolwiek innego, co pisze bezpośrednio do hosta, co może, ale nie musi być przydatne.
JasonMArcher

18
Wziąłem to rozwiązanie i napisałem funkcję, która może być przydatna dla kogoś innego. gist.github.com/2206444 - Przykład: time { ping -n 1 google.com } -Samples 10uruchomi 10czasy poleceń i zwróci średni, minimalny i maksymalny czas. Możesz dodać, -Silentaby połknąć STDOUT.
joshuapoehls

13
Moją preferencją byłoby przypisanie wyniku pomiaru-polecenia zmiennej, takiej jak $t = Measure-Command {<<your command or code block>>}. Wypróbuj go, a następnie wpisać $tw linii poleceń, aby zobaczyć swoje wyniki i wszystkie właściwości, które mają dostęp do, jak $t.Milliseconds, $t.TotalSecondsitp wtedy możemy napisać cokolwiek wyjście chcemy, na przykładWrite-Host That command took $t.TotalSeconds to complete.
Baodad

co jest szybsze w użyciu? net.stopwatch, lub środek-polecenie, lub po prostu porównując dwa zmienne get-date ... (Mam na myśli to, co jest bardziej wydajne, aby zachować na stałe w skrypcie?)
Hicsy

Może zawierać istotę komentarza JasonMArcher (więc jasne jest, że można go użyć w bardziej szczegółowy sposób niż cały skrypt PowerShell)?
Peter Mortensen

183

Możesz także pobrać ostatnie polecenie z historii i odjąć je EndExecutionTimeod niego StartExecutionTime.

.\do_something.ps1  
$command = Get-History -Count 1  
$command.EndExecutionTime - $command.StartExecutionTime

22
Spróbuj tego kiedyś: Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -descaby zobaczyć swój wzór użycia PowerShell według godziny. :-)
Keith Hill

18
+1 za możliwość użycia tego, aby dowiedzieć się, jak długo trwało coś, nawet jeśli nie spodziewałeś się, że zajmie to dużo czasu, gdy zacząłeś, więc nie pomyślałeś, aby owinąć to w Measure-Command.
Chris Magnuson

3
PowerShell jest czasem niesamowity.
ConstantineK,

Chciałbym dać ci coś więcej niż +1 :)
David Ferenczy Rogožan,

Tak, to wspaniale! Zrobiłem liniowiec, używając:$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

Posługiwać się Measure-Command

Przykład

Measure-Command { <your command here> | Out-Host }

Potok do Out-Hostpozwala zobaczyć dane wyjściowe polecenia, które w przeciwnym razie jest zużywane Measure-Command.


Myślę, że masz na myśli Measure-Command {<your command } | Out-Host - Out-Host znajduje się poza blokiem skryptów
Peter McEvoy

1
@Peter - musi znajdować się w bloku, w przeciwnym razie Measure-Command zużywa wyjście, zanim trafi do konsoli.
Droj

1
Gotcha ... w takim przypadku możesz nawet nie potrzebować fajki. Powinien po prostu wydrukować wyniki, o ile nie jest zawinięty w inny blok ....
Droj

2
Czy Out-Default może być lepszy niż Out-Host, ponieważ jest kompatybilny ze skryptami? jsnover.com/blog/2013/12/07/write-host-consanted-harmful
MarcH

1
Cóż, wypróbowałem Out-Default i działa również dobrze w terminalu, więc dlaczego nie zawsze używać Out-Default? (Przepraszam, nie próbowałem)
MarcH

18

Simples

function time($block) {
    $sw = [Diagnostics.Stopwatch]::StartNew()
    &$block
    $sw.Stop()
    $sw.Elapsed
}

następnie można użyć jako

time { .\some_command }

Możesz dostosować dane wyjściowe


1
Measure-Commandukrywa dane wyjściowe polecenia, więc to rozwiązanie jest czasem lepsze.
codekaizen

To fantastyczne rozwiązanie, które szanuje dane wyjściowe polecenia. Możesz także wywoływać go bez nawiasów klamrowych dla prostych poleceń, na przykład: „time ls”, dokładnie tak jak w Uniksie.
Raúl Salinas-Monteagudo

5

Oto funkcja, którą napisałem, która działa podobnie do timepolecenia Unix :

function time {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$command,
        [switch]$quiet = $false
    )
    $start = Get-Date
    try {
        if ( -not $quiet ) {
            iex $command | Write-Host
        } else {
            iex $command > $null
        }
    } finally {
        $(Get-Date) - $start
    }
}

Źródło: https://gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874


Pytanie brzmiało: „Czas wykonania polecenia w PowerShell”. Co to ma wspólnego z synchronizacją procesu przy użyciu Uniksa?
Jean-Claude DeMars,

5
Jest to napisana przeze mnie funkcja programu Powershell, która pokazuje, jak samodzielnie obliczyć czas wykonania w przeciwieństwie do użycia Measure-Commandlub jednego z wielu innych sposobów wykonywania czasu w programie Powershell. Jeśli przeczytasz oryginalne pytanie, poprosił o coś, co działa „jak timepolecenie w Linuksie”.
Bender the Greatest,

3

Korzystanie ze stopera i formatowanie upływającego czasu:

Function FormatElapsedTime($ts) 
{
    $elapsedTime = ""

    if ( $ts.Minutes -gt 0 )
    {
        $elapsedTime = [string]::Format( "{0:00} min. {1:00}.{2:00} sec.", $ts.Minutes, $ts.Seconds, $ts.Milliseconds / 10 );
    }
    else
    {
        $elapsedTime = [string]::Format( "{0:00}.{1:00} sec.", $ts.Seconds, $ts.Milliseconds / 10 );
    }

    if ($ts.Hours -eq 0 -and $ts.Minutes -eq 0 -and $ts.Seconds -eq 0)
    {
        $elapsedTime = [string]::Format("{0:00} ms.", $ts.Milliseconds);
    }

    if ($ts.Milliseconds -eq 0)
    {
        $elapsedTime = [string]::Format("{0} ms", $ts.TotalMilliseconds);
    }

    return $elapsedTime
}

Function StepTimeBlock($step, $block) 
{
    Write-Host "`r`n*****"
    Write-Host $step
    Write-Host "`r`n*****"

    $sw = [Diagnostics.Stopwatch]::StartNew()
    &$block
    $sw.Stop()
    $time = $sw.Elapsed

    $formatTime = FormatElapsedTime $time
    Write-Host "`r`n`t=====> $step took $formatTime"
}

Próbki użycia

StepTimeBlock ("Publish {0} Reports" -f $Script:ArrayReportsList.Count)  { 
    $Script:ArrayReportsList | % { Publish-Report $WebServiceSSRSRDL $_ $CarpetaReports $CarpetaDataSources $Script:datasourceReport };
}

StepTimeBlock ("My Process")  {  .\do_something.ps1 }

-2

Tylko słowo na temat wyciągania (niepoprawnych) wniosków z dowolnych poleceń pomiaru wydajności, o których mowa w odpowiedziach. Istnieje szereg pułapek, które należy wziąć pod uwagę oprócz patrzenia na sam czas wywołania (niestandardowej) funkcji lub polecenia.

Sjoemelsoftware

„Sjoemelsoftware” przegłosowało holenderskie słowo roku 2015
Sjoemelen oznacza oszustwo, a słowo sjoemelsoftware powstało z powodu skandalu emisyjnego Volkswagena. Oficjalna definicja to „oprogramowanie używane do wpływania na wyniki testów”.

Osobiście uważam, że „ Sjoemelsoftware ” nie zawsze jest celowo tworzone w celu oszukiwania wyników testów, ale może wynikać z przystosowania się do praktycznej sytuacji podobnej do przypadków testowych, jak pokazano poniżej.

Jako przykład, za pomocą poleceń wymienionych pomiarów wydajności, LINQ (LINQ) (1) , jest często kwalifikowane jako na czczo sposób coś zrobić i to często jest, ale na pewno nie zawsze! Każdy, kto mierzy wzrost prędkości o współczynnik 40 lub więcej w porównaniu z natywnymi poleceniami PowerShell, prawdopodobnie nieprawidłowo mierzy lub wyciąga błędne wnioski.

Chodzi o to, że niektóre klasy .Net (jak LINQ) używają leniwej oceny (zwanej także odroczonym wykonaniem (2) ). Oznacza to, że przypisanie wyrażenia do zmiennej wydaje się prawie natychmiastowe, ale w rzeczywistości nic jeszcze nie przetworzyło!

Załóżmy, że wklejasz swoje . .\Dosomething.ps1polecenie, które ma albo PowerShell albo bardziej wyrafinowane wyrażenie Linq (dla ułatwienia wyjaśnienia, bezpośrednio osadziłem wyrażenia bezpośrednio w Measure-Command):

$Data = @(1..100000).ForEach{[PSCustomObject]@{Index=$_;Property=(Get-Random)}}

(Measure-Command {
    $PowerShell = $Data.Where{$_.Index -eq 12345}
}).totalmilliseconds
864.5237

(Measure-Command {
    $Linq = [Linq.Enumerable]::Where($Data, [Func[object,bool]] { param($Item); Return $Item.Index -eq 12345})
}).totalmilliseconds
24.5949

Wynik wydaje się oczywisty, późniejsze polecenie Linq jest około 40 razy szybsze niż pierwsze polecenie PowerShell . Niestety nie jest to takie proste ...

Wyświetlmy wyniki:

PS C:\> $PowerShell

Index  Property
-----  --------
12345 104123841

PS C:\> $Linq

Index  Property
-----  --------
12345 104123841

Zgodnie z oczekiwaniami wyniki są takie same, ale jeśli zwrócisz szczególną uwagę, zauważysz, że wyświetlenie $Linqwyników zajęło dużo więcej czasu niż $PowerShellwyników.
Zmierzmy to konkretnie , po prostu pobierając właściwość wynikowego obiektu:

PS C:\> (Measure-Command {$PowerShell.Property}).totalmilliseconds
14.8798
PS C:\> (Measure-Command {$Linq.Property}).totalmilliseconds
1360.9435

Pobranie właściwości obiektu niż obiektu zajęło około 90 razy dłużej i był to tylko jeden obiekt!$Linq$PowerShell

Zauważ też inną pułapkę, że jeśli zrobisz to ponownie, niektóre kroki mogą pojawić się znacznie szybciej niż wcześniej, ponieważ niektóre wyrażenia zostały buforowane.

Podsumowując, jeśli chcesz porównać wydajność między dwiema funkcjami, musisz zaimplementować je w używanym przypadku, rozpocząć od nowej sesji PowerShell i oprzeć swój wniosek na rzeczywistej wydajności kompletnego rozwiązania.

(1) Aby uzyskać więcej informacji na temat PowerShell i LINQ, i przykładów, polecam tihis site: High Performance PowerShell with LINQ
(2) Myślę, że istnieje niewielka różnica między tymi dwiema koncepcjami, ponieważ w przypadku leniwej oceny wynik jest obliczany, gdy jest potrzebny, w odniesieniu do odroczone wykonanie , gdy wynik jest obliczany, gdy system jest bezczynny


Celem tej odpowiedzi jest umożliwienie skierowania ludzi do wspólnego pytania dotyczącego ogólnego nieporozumienia dotyczącego poleceń czasowych w programie PowerShell, tak jak zrobiłem to w przypadku powtarzającego się pytania, takiego jak: Pytanie Powershell - Szukanie najszybszej metody do przejścia przez 500k obiektów szukam dopasowania w kolejnej 500k obiektowej tablicy
iRon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.