PowerShellパフォーマンスの違いフィルターと関数


11

現在、PowerShellに関する洞察を得るために、Windows PowerShell 3.0のステップバイステップブックを読んでいます。

201ページで、作成者は、同じ機能を持つ関数よりもフィルタの方が高速であることを示しています。

このスクリプトは、自分のコンピューターで2.6秒かかります。

MeasureAddOneFilter.ps1
Filter AddOne
{ 
 "add one filter"
  $_ + 1
}

Measure-Command { 1..50000 | addOne }

そしてこれは4.6秒

MeasureAddOneFunction.ps1
Function AddOne
{  
  "Add One Function"
  While ($input.moveNext())
   {
     $input.current + 1
   }
}

Measure-Command { 1..50000 | addOne }

このコードを実行すると、彼の結果の正反対が得られます。

.\MeasureAddOneFilter.ps1
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 226
Ticks             : 2266171
TotalDays         : 2,62288310185185E-06
TotalHours        : 6,29491944444444E-05
TotalMinutes      : 0,00377695166666667
TotalSeconds      : 0,2266171
TotalMilliseconds : 226,6171

.\MeasureAddOneFunction.ps1

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 93
Ticks             : 933649
TotalDays         : 1,08061226851852E-06
TotalHours        : 2,59346944444444E-05
TotalMinutes      : 0,00155608166666667
TotalSeconds      : 0,0933649
TotalMilliseconds : 93,3649

誰かがこれを私に説明できますか?

回答:


13

著者がより多くの裏付けとなる証拠を提供しない限り、おそらく彼はちょうど熱気で満ちていた。あなたはテストを実行し、結果を得て、彼が間違っていることを証明しました。

編集:ジェフリー・スノーバーのブログから:

フィルターは、プロセススクリプトブロックのみを持つ関数です。

どちらも同じプロセスブロックを持っていることを考えると、フィルターだけでは関数よりも速度が有利であることを納得させるにはそれだけでは不十分です。

また、1950年代の機器は、数値に1を追加するのに4.6秒かかるのですか?

PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 7.7266


PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 0.4108

4.6秒は強打です。おそらく、作者はバイナリがngen化される前に、Powershellのある種のCTPバージョンを使用していました。:P

最後に、新しいPowershellセッションでテストを試しますが、逆の順序で試します。最初に関数を試してから2番目にフィルターを試してください。

PS C:\Users\Ryan> Measure-Command { Function AddOne { $_ + 1 }; AddOne 1 }    

TotalMilliseconds : 6.597    


PS C:\Users\Ryan> Measure-Command { Filter AddOne { $_ + 1 }; AddOne 1 }

TotalMilliseconds : 0.4055

見る?最初に実行するものは常に遅くなります。それが関数であるかフィルターであるかに関係なく、2番目の操作をより速くするのは、メモリに既にデータをロードした.NET内部の問題に過ぎません。

ただし、実行回数に関係なく、関数はフィルターよりも一貫して高速であるように見えます。

Measure-Command { Function AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 13.9813

Measure-Command { Filter AddOne($Num) { Return $Num += 1 }; 1..50000 | AddOne $_ }

TotalMilliseconds : 69.5301

だから作者は間違っていた...そして今、私は以前に関数の代わりにフィルターを使用したことがないのを悪くは感じていない。


4

実際、両方のテストで同じ$ _を使用すると、差ははるかに小さくなります。原因は調査しませんでしたが、作成者が両方のテストで同じアプローチを使用していないためと考えられます。また、コンソール出力は結果に干渉する可能性があります。これらの部分をカットすると、数字は非常に似ています。見る:

Function AddOneFunction
{  
    process {
        $_ + 1
    }
}

Filter AddOneFilter
{ 
    $_ + 1
}

write-host "First"
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFilter } | select totalMilliseconds

write-host "Second"
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds
Measure-Command { 1..50000 | AddOneFunction } | select totalMilliseconds

コマンドの順序を変更しても、結果は非常に近くなります。

First

TotalMilliseconds
-----------------
        84.6742
        84.7646
        89.8603
        82.3399
        83.8195
Second
        86.8978
        87.4064
        89.304
        94.4334
        87.0135

ドキュメントには、フィルターは基本的にプロセスブロックのみを含む関数へのショートカットであるとも記載されています。関数は、プロセスブロック(または$ inputなどの自動変数を使用するなどの他の手法)で指定されない限り、1回実行され、入力を使用せず、パイプラインの次のコマンドに渡されません。

詳細については、https://technet.microsoft.com/en-us/library/hh847829.aspxおよびhttps://technet.microsoft.com/en-us/library/hh847781.aspxをご覧ください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.