はじめに
PowerShellの並列処理サンプルここでは、RunspacePoolを使用して並列処理を実現し、非ジェネリックなHashtableではなく、スレッドセーフなConcurrentDictionaryを使用する方法について解説する。
スクリプトの概要
このスクリプトは、3つのカテゴリー(車、動物、植物)の単語リストを並列で処理し、各カテゴリーの単語数をカウントするものである。以下のリンクからスクリプトの全体を確認できる: GitHub リンク
1. 同期Dictionaryの作成
まず、スレッドセーフなConcurrentDictionaryを作成する。これにより、ジョブとメインスクリプト間で情報を安全に共有できる。
1 2 3 4 |
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インスタンスを効率的に管理するためのオブジェクトである。
1 2 3 4 |
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. カテゴリーごとの単語リストを定義
次に、各カテゴリーごとの単語リストを定義する。
1 2 3 4 5 6 7 |
Write-Host "3. カテゴリーごとの単語リストを定義しています..." -ForegroundColor Yellow $categories = @{ "車" = "トヨタ ホンダ 日産 マツダ スバル 三菱 レクサス スズキ ダイハツ" "動物" = "犬 猫 馬 牛 豚 羊 鶏 兎 鼠 象 キリン ライオン トラ クマ パンダ キツネ オオカミ カンガルー コアラ ペンギン イルカ クジラ サメ カバ サイ ゾウ キリン シマウマ カメレオン イグアナ ワニ" "植物" = "桜 梅 椿 菊 向日葵 薔薇 蘭 百合 紫陽花 牡丹 菖蒲 杉 松 竹" } Write-Host " 単語リストの定義が完了しました。" -ForegroundColor Green |
- カテゴリーごとの単語リスト: 各カテゴリーに対応する単語リストを定義。
4. ジョブの作成と開始
エコージョブのスクリプトブロックを作成し、バックグラウンドジョブとして実行する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$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. ジョブの完了を待機しながらリアルタイム出力
ジョブの完了を待ちながら、リアルタイムで出力を表示する。
1 2 3 4 5 6 7 8 9 |
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. 結果の取得と後処理
ジョブの結果を取得し、後処理を行う。
1 2 3 4 5 6 7 8 9 10 11 |
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をクリーンアップする。
1 2 3 4 |
Write-Host "7. RunspacePoolをクリーンアップしています..." -ForegroundColor Yellow $runspacePool.Close() $runspacePool.Dispose() Write-Host " すべてのジョブが完了し、リソースがクリーンアップされました。時刻: $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green |
- RunspacePoolのクリーンアップ:
Close()
およびDispose()
メソッドでリソースを解放。
最終結果の表示
最後に、すべてのジョブの結果を表示する。
1 2 3 4 5 6 7 8 9 |
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 |
最終結果
1 |
このスクリプトは、RunspacePoolを使用して並列処理を行うサンプルです。<br>3つのカテゴリー(車、動物、植物)の単語リストを並列で処理し、各カテゴリーの単語数をカウントします。<br>処理の流れと結果がリアルタイムで表示されます。<br><br>処理の流れ:<br>1. 同期Dictionaryの作成<br>2. RunspacePoolの作成<br>3. カテゴリーごとの単語リストの定義<br>4. ジョブの作成と開始<br>5. ジョブの完了待機とリアルタイム出力<br>6. 結果の取得と表示<br>7. リソースのクリーンアップ<br><br>1. 同期Dictionaryを作成しています...<br> 同期Dictionaryが作成されました。<br>2. RunspacePoolを作成しています...<br> RunspacePoolが作成され、オープンされました。<br>3. カテゴリーごとの単語リストを定義しています...<br> 単語リストの定義が完了しました。<br>4. ジョブを作成して開始しています...<br> ジョブ 'Job植物' が作成され、開始されました。<br>詳細: ジョブ Job植物 を開始しました。時刻: 22:46:56<br> ジョブ 'Job車' が作成され、開始されました。<br> ジョブ 'Job動物' が作成され、開始されました。<br> すべてのジョブが開始されました。時刻: 22:46:56詳細: ジョブ Job車 を開始しました。時刻: 22:46:56<br><br>5. ジョブの完了を待っています...<br>詳細: ジョブ Job植物 を終了しました。時刻: 22:46:57<br>詳細: ジョブ Job動物 を開始しました。時刻: 22:46:57<br>詳細: ジョブ Job動物 を終了しました。時刻: 22:46:58<br>詳細: ジョブ Job車 を終了しました。時刻: 22:46:58<br>6. すべてのジョブが完了しました。結果を取得しています...<br> の結果を取得しています...<br> 結果: ジョブ Job植物 の結果: カテゴリー '植物' の単語数は 14 です。<br> PowerShellインスタンスを破棄しています...<br> の結果を取得しています...<br> 結果: ジョブ Job車 の結果: カテゴリー '車' の単語数は 9 です。<br> PowerShellインスタンスを破棄しています...<br> の結果を取得しています...<br> 結果: ジョブ Job動物 の結果: カテゴリー '動物' の単語数は 31 です。<br> PowerShellインスタンスを破棄しています...<br>7. RunspacePoolをクリーンアップしています...<br> すべてのジョブが完了し、リソースがクリーンアップされました。時刻: 22:46:58<br><br>最終結果:<br>ジョブ Job植物 の結果: カテゴリー '植物' の単語数は 14 です。<br>ジョブ Job車 の結果: カテゴリー '車' の単語数は 9 です。<br>ジョブ Job動物 の結果: カテゴリー '動物' の単語数は 31 です。<br><br>説明:<br>上記の結果は、各ジョブが個別のカテゴリー(車、動物、植物)の単語リストを処理し、その単語数をカウントした結果を示しています。<br>この例では、3つの異なるカテエリーが並列で処理され、それぞれの単語数が計算されました。<br>これにより、並列処理の効果と各カテゴリーの単語数を明確に確認できます。<br> |
コメント