<h3 class="wp-block-heading">はじめに</h3>
<p>PowerShellの並列処理サンプルここでは、RunspacePoolを使用して並列処理を実現し、非ジェネリックなHashtableではなく、スレッドセーフなConcurrentDictionaryを使用する方法について解説する。</p>
<h3 class="wp-block-heading">スクリプトの概要</h3>
<script src="https://gist.github.com/papanda925/8ae2849b0d0ae5f1a482b50d44de47dd.js"></script>
<p>このスクリプトは、3つのカテゴリー(車、動物、植物)の単語リストを並列で処理し、各カテゴリーの単語数をカウントするものである。以下のリンクからスクリプトの全体を確認できる: GitHub リンク</p>
<h3 class="wp-block-heading">1. 同期Dictionaryの作成</h3>
<p>まず、スレッドセーフなConcurrentDictionaryを作成する。これにより、ジョブとメインスクリプト間で情報を安全に共有できる。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Write-Host "1. 同期Dictionaryを作成しています..." -ForegroundColor Yellow
$syncDict = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
$syncDict["Host"] = $Host
Write-Host " 同期Dictionaryが作成されました。" -ForegroundColor Green
</pre>
<ul class="wp-block-list">
<li><strong>ConcurrentDictionary</strong>: スレッドセーフな辞書型コレクション。</li>
<li><code>syncDict["Host"]</code>: PowerShellホストへのアクセスを提供するためのプロパティ。</li>
</ul>
<h3 class="wp-block-heading">2. RunspacePoolの作成</h3>
<p>次に、RunspacePoolを作成して開く。RunspacePoolは、複数のPowerShellインスタンスを効率的に管理するためのオブジェクトである。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Write-Host "2. RunspacePoolを作成しています..." -ForegroundColor Yellow
$runspacePool = [runspacefactory]::CreateRunspacePool(1, 2)
$runspacePool.Open()
Write-Host " RunspacePoolが作成され、オープンされました。" -ForegroundColor Green
</pre>
<ul class="wp-block-list">
<li><strong>RunspacePool</strong>: 複数のPowerShellインスタンスを効率的に管理するためのオブジェクト。</li>
<li><code>CreateRunspacePool(1, 2)</code>: 最小1、最大2のRunspaceを持つプールを作成。</li>
<li><code>Open()</code>: RunspacePoolを開き、使用可能にする。</li>
</ul>
<h3 class="wp-block-heading">3. カテゴリーごとの単語リストを定義</h3>
<p>次に、各カテゴリーごとの単語リストを定義する。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Write-Host "3. カテゴリーごとの単語リストを定義しています..." -ForegroundColor Yellow
$categories = @{
"車" = "トヨタ ホンダ 日産 マツダ スバル 三菱 レクサス スズキ ダイハツ"
"動物" = "犬 猫 馬 牛 豚 羊 鶏 兎 鼠 象 キリン ライオン トラ クマ パンダ キツネ オオカミ カンガルー コアラ ペンギン イルカ クジラ サメ カバ サイ ゾウ キリン シマウマ カメレオン イグアナ ワニ"
"植物" = "桜 梅 椿 菊 向日葵 薔薇 蘭 百合 紫陽花 牡丹 菖蒲 杉 松 竹"
}
Write-Host " 単語リストの定義が完了しました。" -ForegroundColor Green
</pre>
<ul class="wp-block-list">
<li><strong>カテゴリーごとの単語リスト</strong>: 各カテゴリーに対応する単語リストを定義。</li>
</ul>
<h3 class="wp-block-heading">4. ジョブの作成と開始</h3>
<p>エコージョブのスクリプトブロックを作成し、バックグラウンドジョブとして実行する。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">$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
</pre>
<ul class="wp-block-list">
<li><strong>スクリプトブロック</strong>: バックグラウンドジョブとして実行されるコード。</li>
<li><code>BeginInvoke()</code>: ジョブを非同期で開始。</li>
</ul>
<h3 class="wp-block-heading">5. ジョブの完了を待機しながらリアルタイム出力</h3>
<p>ジョブの完了を待ちながら、リアルタイムで出力を表示する。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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
}
</pre>
<ul class="wp-block-list">
<li><strong>リアルタイム出力</strong>: Verboseストリームに出力がある場合、それを読み取って表示。</li>
</ul>
<h3 class="wp-block-heading">6. 結果の取得と後処理</h3>
<p>ジョブの結果を取得し、後処理を行う。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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()
}
</pre>
<ul class="wp-block-list">
<li><strong>結果の取得</strong>: <code>EndInvoke()</code>メソッドでジョブの結果を取得。</li>
<li><strong>リソースの解放</strong>: <code>Dispose()</code>メソッドでリソースを解放。</li>
</ul>
<h3 class="wp-block-heading">7. RunspacePoolのクリーンアップ</h3>
<p>最後に、RunspacePoolをクリーンアップする。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Write-Host "7. RunspacePoolをクリーンアップしています..." -ForegroundColor Yellow
$runspacePool.Close()
$runspacePool.Dispose()
Write-Host " すべてのジョブが完了し、リソースがクリーンアップされました。時刻: $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green
</pre>
<ul class="wp-block-list">
<li><strong>RunspacePoolのクリーンアップ</strong>: <code>Close()</code>および<code>Dispose()</code>メソッドでリソースを解放。</li>
</ul>
<h3 class="wp-block-heading">最終結果の表示</h3>
<p>最後に、すべてのジョブの結果を表示する。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="powershell" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">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
</pre>
<h3 class="wp-block-heading">最終結果</h3>
<pre class="wp-block-preformatted">このスクリプトは、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></pre>
<p></p>
はじめに
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つの異なるカテエリーが並列で処理され、それぞれの単語数が計算されました。
これにより、並列処理の効果と各カテゴリーの単語数を明確に確認できます。
コメント