PowerShell スクリプトのパフォーマンスに関する考慮事項PowerShell scripting performance considerations
.NET を直接利用してパイプラインを回避する PowerShell スクリプトは、慣用的な PowerShell よりも高速になる傾向があります。PowerShell scripts that leverage .NET directly and avoid the pipeline tend to be faster than idiomatic PowerShell. 慣用的な PowerShell は、通常、コマンドレットと PowerShell 関数を頻繁に使用します。多くの場合、パイプラインを利用し、必要な場合にのみ .NET にドロップします。Idiomatic PowerShell typically uses cmdlets and PowerShell functions heavily, often leveraging the pipeline, and dropping down into .NET only when necessary.
注意
ここで説明する手法の多くは、PowerShell の慣用的なではないため、PowerShell スクリプトの読みやすさが低下する可能性があります。Many of the techniques described here are not idiomatic PowerShell and may reduce the readability of a PowerShell script. スクリプト作成者は、それ以外の場合は、慣用的な PowerShell を使用することをお勧めします。Script authors are advised to use idiomatic PowerShell unless performance dictates otherwise.
出力の抑制Suppressing Output
パイプラインへのオブジェクトの書き込みを回避するには、さまざまな方法があります。There are many ways to avoid writing objects to the pipeline:
$null = $arrayList.Add($item)
[void]$arrayList.Add($item)
への割り当て $null
またはへのキャスト [void]
はほぼ同じであり、通常はパフォーマンスが重要な場合に推奨されます。Assignment to $null
or casting to [void]
are roughly equivalent and should generally be preferred where performance matters.
$arrayList.Add($item) > $null
へのファイルのリダイレクト $null
は、前の方法とほとんど同じですが、ほとんどのスクリプトでは違いがわかりません。File redirection to $null
is nearly as good as the previous alternatives, most scripts would never notice the difference.
このシナリオによっては、ファイルのリダイレクトによって若干のオーバーヘッドが生じます。Depending on the scenario, file redirection does introduce a little bit of overhead though.
$arrayList.Add($item) | Out-Null
パイプを別の方法と Out-Null
比較すると、大きなオーバーヘッドが発生します。Piping to Out-Null
has significant overhead when compared to the alternatives.
パフォーマンスに影響するコードでは、これを回避する必要があります。It should be avoiding in performance sensitive code.
$null = . {
$arrayList.Add($item)
$arrayList.Add(42)
}
スクリプトブロックを導入して (ドットソーシングまたはそれ以外の方法を使用して) 呼び出し、その結果をに割り当てること $null
は、スクリプトの大きなブロックの出力を抑制するための便利な手法です。Introducing a script block and calling it (using dot sourcing or otherwise) then assigning the result to $null
is a convenient technique for suppressing the output of a large block of script.
この手法は、にパイプを使用して実行 Out-Null
されるため、パフォーマンスに影響するスクリプトでは回避する必要があります。This technique performs roughly as well as piping to Out-Null
and should be avoided in performance sensitive script.
この例の追加のオーバーヘッドは、以前インラインスクリプトであったスクリプトブロックを作成して呼び出すことから取得されます。The extra overhead in this example comes from the creation of and invoking a script block that was previously inline script.
配列の加算Array Addition
多くの場合、項目のリストを生成するには、加算演算子を使用した配列を使用します。Generating a list of items is often done using an array with the addition operator:
$results = @()
$results += Do-Something
$results += Do-SomethingElse
$results
配列は不変であるため、これは非常に inefficent になる可能性があります。This can be very inefficent because arrays are immutable. 配列に追加するたびに、左側と右の両方のオペランドのすべての要素を保持するために十分な大きさの新しい配列が作成され、その後、両方のオペランドの要素が新しい配列にコピーされます。Each addition to the array actually creates a new array big enough to hold all elements of both the left and right operands, then copies the elements of both operands into the new array. 小さいコレクションの場合、このオーバーヘッドは問題にならない可能性があります。For small collections, this overhead may not matter. 大規模なコレクションの場合、これは明らかに問題になる可能性があります。For large collections, this can definitely be an issue.
代替手段がいくつかあります。There are a couple of alternatives. 実際に配列を必要としない場合は、代わりに ArrayList を使用することを検討してください。If you don't actually require an array, instead consider using an ArrayList:
$results = [System.Collections.ArrayList]::new()
$results.AddRange((Do-Something))
$results.AddRange((Do-SomethingElse))
$results
配列が必要な場合は、独自のを使用して、 ArrayList
ArrayList.ToArray
配列が必要なときにを呼び出すだけで済みます。If you do require an array, you can use your own ArrayList
and simply call ArrayList.ToArray
when you want the array.
または、PowerShell でとを作成することもでき ArrayList
Array
ます。Alternatively, you can let PowerShell create the ArrayList
and Array
for you:
$results = @(
Do-Something
Do-SomethingElse
)
この例では、PowerShell によって、 ArrayList
配列式内のパイプラインに書き込まれた結果を保持するが作成されます。In this example, PowerShell creates an ArrayList
to hold the results written to the pipeline inside the array expression.
をに割り当てる直前に、 $results
PowerShell はをに変換し ArrayList
object[]
ます。Just before assigning to $results
, PowerShell converts the ArrayList
to an object[]
.
大きなファイルの処理Processing Large Files
PowerShell でファイルを処理する慣用的なの方法は、次のようになります。The idiomatic way to process a file in PowerShell might look something like:
Get-Content $path | Where-Object { $_.Length -gt 10 }
これは、.NET Api を直接使用するよりもはるかに低い順序で実行できます。This can be nearly an order of magnitude slower than using .NET APIs directly:
try
{
$stream = [System.IO.StreamReader]::new($path)
while ($line = $stream.ReadLine())
{
if ($line.Length -gt 10)
{
$line
}
}
}
finally
{
$stream.Dispose()
}
Write-Host しないAvoid Write-Host
一般に、出力をコンソールに直接書き込むことは不適切であると考えられますが、意味がある場合は、多くのスクリプトでが使用さ Write-Host
れます。It is generally considered poor practice to write output directly to the console, but when it makes sense, many scripts use Write-Host
.
多くのメッセージをコンソールに書き込む必要がある場合は、 Write-Host
よりもはるかに低い順序にすることができ [Console]::WriteLine()
ます。If you must write many messages to the console, Write-Host
can be an order of magnitude slower than [Console]::WriteLine()
. ただし、 [Console]::WriteLine()
は powershell.exe や powershell_ise.exe などの特定のホストに適した代替手段であることに注意してください。すべてのホストで動作する保証はありません。However, be aware that [Console]::WriteLine()
is only a suitable alternative for specific hosts like powershell.exe or powershell_ise.exe - it's not guaranteed to work in all hosts.
を使用する代わり Write-Host
に、 書き込み出力の使用を検討してください。Instead of using Write-Host
, consider using Write-Output.