Muni Bus

パソコンの操作方法や設定方法を忘れないようにメモしています。ブログを一回引っ越ししているので、所々表示がかなり乱れています・・・

【PowerShell】パイプライン利用による繰り返し処理の高速化

次の3つのスクリプトは、C:\Windows\System32以下のすべてのファイルとそのファイルサイズを一覧形式でCSV形式のファイルに出力するスクリプトである。それぞれ全く同じ結果が得られる。

1番目(mc1.ps1)は、ファイルの一覧を変数にすべて格納し、その後、繰り返し処理で文字列配列に格納して一括出力をしている。2番目(mc2.ps1)は、ファイル一覧をパイプラインを次に渡して配列に格納し、最後にまとめてファイルに出力している。3番目(mc3.ps1)は、ファイル一覧の取得からファイルへの出力までを、すべてパイプラインでつなげて処理している。

mc1.ps1

$list = Get-ChildItem -Recurse -ErrorAction SilentlyContinue C:\Windows\System32
$s = @()
foreach ($file in $list) {
    $s += [String]::Format("{0},{1}", $file.Name, $file.Length)
}
$s | Out-File output1.csv

mc2.ps1

$s = @()
Get-ChildItem -Recurse -ErrorAction SilentlyContinue C:\Windows\System32 |
% {
	$s += [String]::Format("{0},{1}", $_.Name, $_.Length)
}
$s | Out-File output2.csv

mc3.ps1

Get-ChildItem -Recurse -ErrorAction SilentlyContinue C:\Windows\System32 | % {
    [String]::Format("{0},{1}", $_.Name, $_.Length)
} | Out-File output3.csv

これら3つのスクリプトによる処理時間を比べてみる(複数回事前に動作させた後に行っており、実行順で大きな差が出るようなことはない)。

PS > (Measure-Command {.\mc1.ps1}).TotalSeconds
6.4441259
PS > (Measure-Command {.\mc2.ps1}).TotalSeconds
5.6466201
PS > (Measure-Command {.\mc3.ps1}).TotalSeconds
1.1454969

1番目より2番目のほうが早く、3番目は1番目より約6倍速い。 オブジェクトを取得して繰り返し処理を行う場合は、パイプラインを使用してオブジェクトをそのまま次に渡すような書き方をすれば、処理が早くなる。