PowerShellでのコマンド実行のタイミング


217

Linuxの「time」コマンドのように、PowerShellでコマンドの実行を時間測定する簡単な方法はありますか?
私はこれを思いつきました:

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

しかし、私はもっと簡単なものを望みます

time .\do_something.ps1

回答:


337

うん。

Measure-Command { .\do_something.ps1 }

のマイナーな欠点の1つ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 | Out-Default}。または、ホストに直接書き込むその他のもの。これは有用な場合とそうでない場合があります。
JasonMArcher、2010

18
私はこの解決策を取り、他の誰かに役立つかもしれない関数を書きました。gist.github.com/2206444-例:time { ping -n 1 google.com } -Samples 10コマンド10時間を実行し、かかった平均時間、最小時間、最大時間を返します。-SilentSTDOUTを飲み込むことができます。
joshuapoehls 2012年

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、または単に2つのget-date変数を比較する...(
つまり

おそらく、JasonMArcherのコメントの要点を含めてください(PowerShellスクリプト全体よりもきめ細かく使用できることは明らかです)?
Peter Mortensen、

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
これを使用して、開始時に長い時間がかかることを予期していなかったため、Measure-Commandでラップすることを考えていなかった場合でも、どれくらいの時間がかかったかを調べることができるための+1。
Chris Magnuson、2015

3
powershellは時々素晴らしいです。
ConstantineK

私はあなたに+1よりも多くを与えることができればいいのに:)
David FerenczyRogožan2018年

はい、これは素晴らしいです!私は次のものを使用してワンライナーを作りました:$command = Get-History -Count 1 ; "{0}" -f ($command.EndExecutionTime - $command.StartExecutionTime)
Phil

106

使用する Measure-Command

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

パイプをOut-Host使用すると、コマンドの出力を確認できます。この出力は、通常はによって使用されMeasure-Commandます。


私はあなたが意味を考えるMeasure-Command {<your command } | Out-Host -アウト・ホストは、スクリプトブロックの外にある
ピーターMcEvoyさん

1
@Peter-ブロック内にある必要があります。そうでない場合、Measure-Commandはコンソールに移動する前に出力を消費します。
Droj

1
おっと...その場合、パイプさえ必要ないかもしれません。あなたはそれが....他のいくつかのブロックに包まれていない限り、それはちょうど、結果を印刷する必要があります
Droj

2
スクリプトと互換性があるため、Out-Defaultは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 2018年

これは、コマンドの出力を尊重する素晴らしいソリューションです。単純なコマンドの場合は、中括弧なしで呼び出すこともできます。たとえば、「time ls」は、Unixの場合とまったく同じです。
ラウル・サリナス- Monteagudo

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を使用してプロセスのタイミングを決定することとは何ですか?
Jean-Claude DeMars 2017

5
これは私が書いたPowershell関数で、Powershellで実行時間を計測しMeasure-Commandたり、さまざまな方法で実行したりするのではなく、自分で実行時間を計算する方法を示しています。元の質問を読んだ場合、彼は「timeLinux のコマンドのように」機能するものを求めました。
Bender the Greatest

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

回答で参照されているパフォーマンス測定コマンドのいずれかから(誤った)結論を導き出すことについてのちょっとした言葉。(カスタム)関数またはコマンドの最低限の呼び出し時間を確認することを除いて、考慮すべきいくつかの落とし穴があります。

Sjoemelソフトウェア

「シェーメルソフト」が2015年のオランダ語で投票
シェーメーレンは不正行為を意味し、シェーメルソフトウェアという言葉はフォルクスワーゲンの排出スキャンダルが原因となった。公式の定義は「テスト結果に影響を与えるために使用されるソフトウェア」です。

個人的には、「Sjoemelsoftware」は必ずしも意図的にテスト結果をだますためのものではなく、以下に示すようなテストケースに似た現実的な状況から生まれたものだと思います。

例として、リストされているパフォーマンス測定コマンドであるLanguage Integrated Query(LINQ)(1)を使用すると、多くの場合、何かを実行するため高速な方法と見なされます。ネイティブのPowerShellコマンドと比較して40倍以上の速度の増加を測定する人は、おそらく誤った測定または誤った結論を出しているでしょう。

重要なのは、遅延評価を使用する一部の.Netクラス(LINQなど)(遅延実行(2)とも呼ばれる)です。つまり、式を変数に代入すると、ほとんどすぐに実行されたように見えますが、実際にはまだ何も処理していません。

PowerShellまたはより高度なLinq式のいずれかを含むコマンドをドットソース化するとします. .\Dosomething.ps1(説明を簡単にするために、式を直接に直接埋め込みました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コマンドは、最初のPowerShellコマンドよりも約40倍高速です。残念ながら、それはそれほど簡単ではありません ...

結果を表示しましょう:

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オブジェクトだけでした。

また、もう一度実行すると、一部のステップが以前よりもはるかに速く表示される可能性があるという他の落とし穴にも注意してください。これは、一部の式がキャッシュされているためです。

結論として、2つの関数のパフォーマンスを比較したい場合は、使用した場合にそれらを実装し、新しいPowerShellセッションから始めて、ソリューション全体の実際のパフォーマンスに基づいて結論を出す必要があります。

(1)PowerShellとLINQの背景と例については、次のサイトをお勧めします:LINQを使用した高性能PowerShell
(2)遅延評価場合、結果は必要に応じて計算されるため、2つの概念には小さな違いがあると思いますシステムがアイドル状態のときに結果が計算される遅延実行


この回答の目的は、PowerShellの質問の繰り返しの場合と同様に、PowerShellのタイミングコマンドに関する一般的な誤解について一般的な質問を紹介できるようにすることです:Powershellの質問-500kオブジェクトをループする最速の方法を探しています別の500kオブジェクト配列で一致を探す
iRon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.