Час виконання команди в PowerShell


217

Чи існує такий простий спосіб встановити час виконання команди в PowerShell, як команда 'time' в 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, або вимірювання-командування, або просто порівняння двох варіантів дати отримання ... (я маю на увазі, що ефективніше постійно зберігати у сценарії?)
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
Іноді надзвичайна ситуація.
КонстантинК

Я б хотів, щоб я міг тобі дати більше ніж +1 :)
Девід Ференчі Рогожан

Так, це чудово! Я зробив $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.


Я думаю, ти маєш на увазі Measure-Command {<your command } | Out-Host - Аут-хост знаходиться поза блоком сценаріїв
Пітер МакЕвой

1
@Peter - він повинен знаходитися всередині блоку, інакше Measure-Command споживає вихід, перш ніж він перейде до консолі.
Дрой

1
Отримав ... у цьому випадку вам може навіть не потрібна труба. Він повинен просто надрукувати результати, якщо ви не
загорнете

2
Чи Out-Host може бути кращим, ніж Out-Host, оскільки сумісний із сценарієм? jsnover.com/blog/2013/12/07/write-host-considered-harmful
MarcH

1
Добре я спробував Out-Default, і він працює чудово і в терміналі, то чому б не використовувати Out-Default завжди? (Я не пробував цього в сценарії вибачте)
MarcH

18

Симплекс

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

то може використовувати як

time { .\some_command }

Ви можете налаштувати вихід


1
Measure-Commandприховує вихід команди, тому таке рішення іноді краще.
codekaizen

Це фантастичне рішення, яке поважає вихід команди. Ви також можете викликати його без фігурних дужок для простих команд, наприклад: "time ls", точно так, як це було б в Unix.
Рауль Салінас-Монтеагудо

5

Ось функція, яку я написав, яка працює аналогічно timeкоманді 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
    }
}

Джерело: 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 }

-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, як я щойно робив для повторного запитання на кшталт: Питання Поуершелла - Шукаю найшвидший метод провести цикл через об'єкти 500k шукаємо збіг в іншому масиві об'єктів 500k
iRon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.