はじめに
PowerShellの並列処理サンプルここでは、RunspacePoolを使用して並列処理を実現し、非ジェネリックなHashtableではなく、スレッドセーフなConcurrentDictionaryを使用する方法について解説する。
スクリプトの概要
このスクリプトは、3つのカテゴリー(車、動物、植物)の単語リストを並列で処理し、各カテゴリーの単語数をカウントするものである。以下のリンクからスクリプトの全体を確認できる: GitHub リンク
1. 同期Dictionaryの作成
まず、スレッドセーフなConcurrentDictionaryを作成する。これにより、ジョブとメインスクリプト間で情報を安全に共有できる。
Write-Host "1. 同期Dictionaryを作成しています..." -ForegroundColor Yellow $syncDict = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new() $syncDict["Host"] = $Host Write-Host " 同期Dictionaryが作成されました。" -ForegroundColor Green
- ConcurrentDictionary: スレッドセーフな辞書型コレクション。
syncDict["Host"]
: PowerShellホストへのアクセスを提供するためのプロパティ。
2. RunspacePoolの作成
次に、RunspacePoolを作成して開く。RunspacePoolは、複数のPowerShellインスタンスを効率的に管理するためのオブジェクトである。
Write-Host "2. RunspacePoolを作成しています..." -ForegroundColor Yellow $runspacePool = [runspacefactory]::CreateRunspacePool(1, 2) $runspacePool.Open() Write-Host " RunspacePoolが作成され、オープンされました。" -ForegroundColor Green
- RunspacePool: 複数のPowerShellインスタンスを効率的に管理するためのオブジェクト。
CreateRunspacePool(1, 2)
: 最小1、最大2のRunspaceを持つプールを作成。Open()
: RunspacePoolを開き、使用可能にする。
3. カテゴリーごとの単語リストを定義
次に、各カテゴリーごとの単語リストを定義する。
Write-Host "3. カテゴリーごとの単語リストを定義しています..." -ForegroundColor Yellow $categories = @{ "車" = "トヨタ ホンダ 日産 マツダ スバル 三菱 レクサス スズキ ダイハツ" "動物" = "犬 猫 馬 牛 豚 羊 鶏 兎 鼠 象 キリン ライオン トラ クマ パンダ キツネ オオカミ カンガルー コアラ ペンギン イルカ クジラ サメ カバ サイ ゾウ キリン シマウマ カメレオン イグアナ ワニ" "植物" = "桜 梅 椿 菊 向日葵 薔薇 蘭 百合 紫陽花 牡丹 菖蒲 杉 松 竹" } Write-Host " 単語リストの定義が完了しました。" -ForegroundColor Green
- カテゴリーごとの単語リスト: 各カテゴリーに対応する単語リストを定義。
4. ジョブの作成と開始
エコージョブのスクリプトブロックを作成し、バックグラウンドジョブとして実行する。
$scriptBlock = { param($category, $words, $jobName, $syncDict) $syncDict["Host"].UI.WriteVerboseLine("ジョブ $jobName を開始しました。時刻: $(Get-Date -Format 'HH:mm:ss')") $wordCount = ($words -split '\s+').Count Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 3) $syncDict["Host"].UI.WriteVerboseLine("ジョブ $jobName を終了しました。時刻: $(Get-Date -Format 'HH:mm:ss')") return "ジョブ $jobName の結果: カテゴリー '$category' の単語数は $wordCount です。" } Write-Host "4. ジョブを作成して開始しています..." -ForegroundColor Yellow $jobs = @() $categories.GetEnumerator() | ForEach-Object { $powershell = [powershell]::Create().AddScript($scriptBlock).AddArgument($_.Key).AddArgument($_.Value).AddArgument("Job$($_.Key)").AddArgument($syncDict) $powershell.RunspacePool = $runspacePool $jobs += @{ PowerShell = $powershell Handle = $powershell.BeginInvoke() } Write-Host " ジョブ 'Job$($_.Key)' が作成され、開始されました。" -ForegroundColor Green } Write-Host " すべてのジョブが開始されました。時刻: $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green
- スクリプトブロック: バックグラウンドジョブとして実行されるコード。
BeginInvoke()
: ジョブを非同期で開始。
5. ジョブの完了を待機しながらリアルタイム出力
ジョブの完了を待ちながら、リアルタイムで出力を表示する。
Write-Host "5. ジョブの完了を待っています..." -ForegroundColor Yellow while ($jobs.Handle.IsCompleted -contains $false) { foreach ($job in $jobs) { if ($job.PowerShell.Streams.Verbose.Count -gt 0) { $job.PowerShell.Streams.Verbose.ReadAll() | ForEach-Object { Write-Host " $_" -ForegroundColor Magenta } } } Start-Sleep -Milliseconds 100 }
- リアルタイム出力: Verboseストリームに出力がある場合、それを読み取って表示。
6. 結果の取得と後処理
ジョブの結果を取得し、後処理を行う。
Write-Host "6. すべてのジョブが完了しました。結果を取得しています..." -ForegroundColor Yellow $results = @() foreach ($job in $jobs) { $jobName = $job.PowerShell.Commands.Commands[0].Parameters['jobName'].Value Write-Host " $jobName の結果を取得しています..." -ForegroundColor Blue $result = $job.PowerShell.EndInvoke($job.Handle) $results += $result Write-Host " 結果: $result" -ForegroundColor Green Write-Host " PowerShellインスタンスを破棄しています..." -ForegroundColor Blue $job.PowerShell.Dispose() }
- 結果の取得:
EndInvoke()
メソッドでジョブの結果を取得。 - リソースの解放:
Dispose()
メソッドでリソースを解放。
7. RunspacePoolのクリーンアップ
最後に、RunspacePoolをクリーンアップする。
Write-Host "7. RunspacePoolをクリーンアップしています..." -ForegroundColor Yellow $runspacePool.Close() $runspacePool.Dispose() Write-Host " すべてのジョブが完了し、リソースがクリーンアップされました。時刻: $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green
- RunspacePoolのクリーンアップ:
Close()
およびDispose()
メソッドでリソースを解放。
最終結果の表示
最後に、すべてのジョブの結果を表示する。
Write-Host "`n最終結果:" -ForegroundColor Cyan $results | ForEach-Object { Write-Host $_ -ForegroundColor White } Write-Host "`n説明:" -ForegroundColor Cyan Write-Host "上記の結果は、各ジョブが個別のカテゴリー(車、動物、植物)の単語リストを処理し、その単語数をカウントした結果を示している。" -ForegroundColor White Write-Host "この例では、3つの異なるカテゴリーが並列で処理され、それぞれの単語数が計算された。" -ForegroundColor White Write-Host "これにより、並列処理の効果と各カテゴリーの単語数を明確に確認できる。" -ForegroundColor White
最終結果
このスクリプトは、RunspacePoolを使用して並列処理を行うサンプルです。
3つのカテゴリー(車、動物、植物)の単語リストを並列で処理し、各カテゴリーの単語数をカウントします。
処理の流れと結果がリアルタイムで表示されます。
処理の流れ:
1. 同期Dictionaryの作成
2. RunspacePoolの作成
3. カテゴリーごとの単語リストの定義
4. ジョブの作成と開始
5. ジョブの完了待機とリアルタイム出力
6. 結果の取得と表示
7. リソースのクリーンアップ
1. 同期Dictionaryを作成しています...
同期Dictionaryが作成されました。
2. RunspacePoolを作成しています...
RunspacePoolが作成され、オープンされました。
3. カテゴリーごとの単語リストを定義しています...
単語リストの定義が完了しました。
4. ジョブを作成して開始しています...
ジョブ 'Job植物' が作成され、開始されました。
詳細: ジョブ Job植物 を開始しました。時刻: 22:46:56
ジョブ 'Job車' が作成され、開始されました。
ジョブ 'Job動物' が作成され、開始されました。
すべてのジョブが開始されました。時刻: 22:46:56詳細: ジョブ Job車 を開始しました。時刻: 22:46:56
5. ジョブの完了を待っています...
詳細: ジョブ Job植物 を終了しました。時刻: 22:46:57
詳細: ジョブ Job動物 を開始しました。時刻: 22:46:57
詳細: ジョブ Job動物 を終了しました。時刻: 22:46:58
詳細: ジョブ Job車 を終了しました。時刻: 22:46:58
6. すべてのジョブが完了しました。結果を取得しています...
の結果を取得しています...
結果: ジョブ Job植物 の結果: カテゴリー '植物' の単語数は 14 です。
PowerShellインスタンスを破棄しています...
の結果を取得しています...
結果: ジョブ Job車 の結果: カテゴリー '車' の単語数は 9 です。
PowerShellインスタンスを破棄しています...
の結果を取得しています...
結果: ジョブ Job動物 の結果: カテゴリー '動物' の単語数は 31 です。
PowerShellインスタンスを破棄しています...
7. RunspacePoolをクリーンアップしています...
すべてのジョブが完了し、リソースがクリーンアップされました。時刻: 22:46:58
最終結果:
ジョブ Job植物 の結果: カテゴリー '植物' の単語数は 14 です。
ジョブ Job車 の結果: カテゴリー '車' の単語数は 9 です。
ジョブ Job動物 の結果: カテゴリー '動物' の単語数は 31 です。
説明:
上記の結果は、各ジョブが個別のカテゴリー(車、動物、植物)の単語リストを処理し、その単語数をカウントした結果を示しています。
この例では、3つの異なるカテエリーが並列で処理され、それぞれの単語数が計算されました。
これにより、並列処理の効果と各カテゴリーの単語数を明確に確認できます。
コメント