Powershellが遅いなら、コストのかからない方法を考えよう特集第四弾です。
PowerShellでFor / Foreach / Foreach-Object / ScriptBlock / Filterのベンチマーク In English : PowerShell For / Foreach / Foreach-Object / ScriptBlock / Filter – Benchmark 2013 PowerShellのForeach-Objectは一体何をしているのか PowerShellでSubstitute(変数代入)、Host(ホスト出力)、Content(ファイル出力)するコストのベンチマーク
PowerShellで結果がホスト表示される時にNull破棄をしたいことは多々あります。 そして、Null破棄はやり方が色々あります。 そこで、今回はNull破棄で最もコストがかからず実行速度に影響を与えない方法を考えてみます。
UserVoice にもあったりしたり。
performance of out-null drastically worse then using [void] or assigning result to $null
Votes from Connect: 4
Original Date Submitted: 3/28/2015 6:08:31 AM
Description:
********Contact Information********
Handle: JasonHorner
Site Name: PowerShell
Feedback ID: 1208677
***************************************
Frequency: PowerShell
Regression: gci | out-null
[void](gci)...
Null破棄をする方法
まずNull破棄をする手段を考えてみましょう。
{ScriptBlock} | Out-Null [Void]{ScriptBlock} {ScriptBlock} > $null $null = {ScriptBlock}
以上の4つがぱっと思いつきます。
テストコード
では、それぞれのベンチマークを取ることでコストを考えます。 テスト1 以下のコードで1..1000を生成実行する際のベンチを10000回実行して平均を取りました。
# Null破棄しない 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000)} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # | out-Null 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000) | Out-Null} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # [void] 1..10000 | ForEach-Object{ [double](Measure-Command {[Void]$(1..1000)} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # > $null 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000) > $null} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # $null = 1..10000| ForEach-Object{ [double](Measure-Command {$null = $(1..1000)} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average
テスト2 以下のコードは、1..1000を生成し、[int]型チェックする際のベンチを10000回実行して平均を取りました。
# Null破棄しない 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000) | where {$_ -is [int]}} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # | out-Null 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000) | where {$_ -is [int] | Out-Null}} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # [void]は、Cast出来ないため省きます。 # > $null 1..10000 | ForEach-Object{ [double](Measure-Command {$(1..1000) | where {$_ -is [int]> $null}} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average # $null = 1..10000| ForEach-Object{ [double](Measure-Command {$null = $(1..1000) | where {$_ -is [int]}} | select -ExpandProperty TotalMilliseconds) } | Measure-Object -Average
ベンチ結果
ベンチ結果です。
Null Operation | Test1 | Test2 |
None | 0.29 | 95.93 |
Out-Null | 21.59 | 224.24 |
[void] | 0.19 | - |
> $null | 0.17 | 100.04 |
$null = | 0.22 | 99.10 |
まとめ
以上から、Null破棄する際に | Out-Nullをすることはもってのほかと分かります(おい ついパイプでつなげられるので使ってしまうのですが…… > $nullが読みやすさも良いですねー。 [void]は型変換できないパターンが多いので、Add-Typeとかぐらいにですかねーw いずれにしても、| Out-Nullさえつかわなければ問題なさそうなので良かったですね。
参考サイト
Whats the better (cleaner) way to ignore output in PowerShell