Сроки выполнения команды в PowerShell

217

Есть ли простой способ рассчитать время выполнения команды в PowerShell, например, команду «время» в Linux?
Я придумал это:

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

Но я хотел бы что-то более простое, как

time .\do_something.ps1
Паоло Тедеско
источник

Ответы:

337

Ага.

Measure-Command { .\do_something.ps1 }

Обратите внимание, что одним незначительным недостатком Measure-Commandявляется то, что вы не видите stdoutвывода.

[Обновление, спасибо @JasonMArcher] Вы можете исправить это, отправив вывод команды в какой-то командлет, который пишет на хост, например, Out-Defaultтак:

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

Еще один способ увидеть результат - использовать Stopwatchкласс .NET следующим образом:

$sw = [Diagnostics.Stopwatch]::StartNew()
.\do_something.ps1
$sw.Stop()
$sw.Elapsed
Кит Хилл
источник
114
Вы также можете увидеть вывод, как это, Measure-Command {ps | Из-умолчанию}. Или что-нибудь еще, что пишет напрямую на хост, что может или не может быть полезным.
JasonMArcher
18
Я взял это решение и написал функцию, которая может быть полезна кому-то еще. gist.github.com/2206444 - Пример: time { ping -n 1 google.com } -Samples 10запустит время команды 10и вернет среднее, минимальное и максимальное время выполнения. Вы можете добавить, -Silentчтобы проглотить STDOUT.
joshuapoehls
13
Я предпочел бы присвоить результат Measure-Command переменной, например $t = Measure-Command {<<your command or code block>>}. Попробуйте, а затем введите $tв приглашении, чтобы увидеть ваши результаты и все свойства, к которым у вас есть доступ, например $t.Milliseconds, $t.TotalSecondsи т. Д. Затем мы можем записать любой вывод, например,Write-Host That command took $t.TotalSeconds to complete.
Baodad
что быстрее использовать? net.stopwatch, или measure-command, или просто сравнивая две переменные get-date ... (я имею в виду, что более эффективно постоянно сохранять в сценарии?)
Hicsy
Возможно, включить суть комментария JasonMArcher (чтобы было ясно, что его можно использовать более детально, чем весь сценарий PowerShell)?
Питер Мортенсен
183

Вы также можете получить последнюю команду из истории и вычесть ее EndExecutionTimeиз своей StartExecutionTime.

.\do_something.ps1  
$command = Get-History -Count 1  
$command.EndExecutionTime - $command.StartExecutionTime
Шей Леви
источник
22
Попробуйте это как-нибудь: Get-History | Group {$_.StartExecutionTime.Hour} | sort Count -descувидеть схему использования PowerShell по часам дня. :-)
Кит Хилл
18
+1 за возможность использовать это, чтобы узнать, сколько времени заняло что-то, даже если вы не ожидали, что это займет много времени, когда вы начали, поэтому вы не думали оборачивать это в Measure-Command.
Крис Магнусон
3
PowerShell это круто иногда.
КонстантинK
Я хотел бы дать вам больше, чем просто +1 :)
David Ferenczy Rogožan
Да, это здорово! Я сделал одну $command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Фил
106

использование Measure-Command

пример

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

Канал, Out-Hostпозволяющий вам увидеть выходные данные команды, которая в противном случае используется Measure-Command.

Droj
источник
Я думаю, вы имеете в виду Measure-Command {<your command } | Out-Host - Out-Host находится за пределами блока сценариев
Питер МакЭвой
1
@Peter - он должен находиться внутри блока, в противном случае Measure-Command потребляет вывод перед тем, как перейти к консоли.
Дрой
1
Понятно ... в этом случае вам может даже не понадобиться труба. Он должен просто напечатать результаты, если только вы не завернули их в какой-то другой блок ....
Дрой
2
Возможно, Out-Default лучше, чем Out-Host, потому что он совместим со сценариями? jsnover.com/blog/2013/12/07/write-host-considered-harmful
19
1
Ну, я попробовал Out-Default, и он отлично работает в терминале, так почему бы не использовать Out-Default всегда? (Я не пробовал его в сценарии извините)
МАРТ
18

Simples

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

затем можно использовать как

time { .\some_command }

Вы можете настроить выход

Майк Вест
источник
1
Measure-Commandскрывает вывод команды, так что это решение иногда лучше.
Codekaizen
Это фантастическое решение, которое учитывает вывод команды. Вы также можете вызвать его без фигурных скобок для простых команд, например: «time ls», точно так же, как в Unix.
Рауль Салинас-Монтеагудо
5

Вот функция, которую я написал, которая работает аналогично команде Unix time:

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
    }
}

Источник: https://gist.github.com/bender-the-greatest/741f696d965ed9728dc6287bdd336874

Бендер Величайший
источник
Вопрос был «Время выполнения команды в PowerShell». Какое это имеет отношение к синхронизации процесса с использованием Unix?
Жан-Клод ДеМарс
5
Я написал эту функцию Powershell, которая показывает, как самостоятельно рассчитать время выполнения, в отличие от использования Measure-Commandили одного из различных других способов измерения времени выполнения в Powershell. Если вы прочитали оригинальный вопрос, он попросил что-то, что работает «как timeкоманда в Linux».
Бендер Величайший
3

Использование секундомера и форматирование прошедшего времени:

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"
}

Образцы использования

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

StepTimeBlock ("My Process")  {  .\do_something.ps1 }
Kiquenet
источник
-2

Просто слово о том, как сделать (неправильные) выводы из любой из команд измерения производительности, указанных в ответах. Существует ряд ловушек, которые следует принимать во внимание, помимо рассмотрения времени простейшего вызова (пользовательской) функции или команды.

Sjoemelsoftware

«Sjoemelsoftware» проголосовало за голландское слово 2015 года «
Sjoemelen» означает «обман», а слово « sjoemelsoftware» появилось в связи со скандалом с выбросами Volkswagen. Официальное определение - «программное обеспечение, используемое для влияния на результаты испытаний».

Лично я считаю, что « Sjoemelsoftware » не всегда намеренно создается для того, чтобы обманывать результаты тестов, но может возникать в результате практической ситуации, которая похожа на тестовые примеры, показанные ниже.

В качестве примера, используя перечисленные команды измерения производительности, Language Integrated Query (LINQ) (1) , часто квалифицируется как на голодном способ получить что - то сделать , и это часто бывает, но , конечно , не всегда! Любой, кто измеряет увеличение скорости в 40 или более раз по сравнению с собственными командами PowerShell, вероятно, неправильно измеряет или делает неправильный вывод.

Дело в том, что некоторые классы .Net (например, LINQ) используют ленивую оценку (также называемую отложенным выполнением (2) ). Это означает, что когда вы присваиваете выражение переменной, оно почти сразу кажется выполненным, но на самом деле оно еще ничего не обрабатывает!

Предположим, что у вас есть точечный источник вашей . .\Dosomething.ps1команды, которая имеет либо PowerShell, либо более сложное выражение Linq (для простоты объяснения я непосредственно встроил выражения непосредственно в 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

Результат кажется очевидным, более поздняя команда Linq примерно в 40 раз быстрее, чем первая команда PowerShell . К сожалению, не все так просто ...

Давайте выведем результаты:

PS C:\> $PowerShell

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

PS C:\> $Linq

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

Как и ожидалось, результаты такие же, но если вы обратили пристальное внимание, вы заметите, что отображение $Linqрезультатов заняло гораздо больше времени, чем $PowerShellрезультаты.
Давайте определим это , просто получив свойство полученного объекта:

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

Потребовалось примерно в 90 раз больше времени для извлечения свойства $Linqобъекта, чем $PowerShellобъекта, и это был всего лишь один объект!

Также обратите внимание на другую ловушку, что если вы сделаете это снова, некоторые шаги могут появиться намного быстрее, чем раньше, это потому, что некоторые выражения были кэшированы.

В итоге, если вы хотите сравнить производительность между двумя функциями, вам нужно будет реализовать их в используемом вами случае, начать с нового сеанса PowerShell и основывать свои выводы на фактической производительности полного решения.

(1) Для получения дополнительной информации и примеров по PowerShell и LINQ я рекомендую этот сайт: Высокопроизводительный PowerShell с LINQ (2) Я думаю, что между этими
двумя концепциями есть небольшое различие, так как при ленивой оценке результат вычисляется при необходимости применительно к отсроченное выполнение, в котором результат вычисляется, когда система простаивает

железо
источник
Цель этого ответа состоит в том, чтобы иметь возможность отсылать людей к общему вопросу для общего заблуждения относительно команд синхронизации в PowerShell, как я только что сделал для повторяющегося вопроса, такого как: вопрос Powershell - в поисках самого быстрого метода для циклического прохождения объектов размером 500 тыс. ищет совпадение в другом массиве объектов
500 тыс.