PowerShellで非同期処理:RunspaceとConcurrentDictionaryを活用したエコー処理

Tech

はじめに

PowerShellで複雑なタスクを効率的に処理するためには、非同期処理が必要になることもあるかも。その時に備えて、Runspaceを使用して非同期処理を実現し、非ジェネリックなHashtableではなく、スレッドセーフなConcurrentDictionaryを使用する方法を解説。

スクリプトの概要

1. RunspacePoolの作成

まず、RunspacePoolを作成して開く。RunspacePoolは、複数のPowerShellインスタンスを効率的に管理するためのオブジェクトである。

Write-Host "1. RunspacePoolを作成しています..." -ForegroundColor Yellow
$runspacePool = [runspacefactory]::CreateRunspacePool(1, 1)
$runspacePool.Open()
Write-Host "   RunspacePoolが作成され、オープンされました。" -ForegroundColor Green
  • RunspacePool: 複数のPowerShellインスタンスを効率的に管理するためのオブジェクト。
  • CreateRunspacePool(1, 1): 最小1、最大1のRunspaceを持つプールを作成。
  • Open(): RunspacePoolを開き、使用可能にする。

2. 同期Dictionaryの作成

次に、スレッドセーフなConcurrentDictionaryを作成する。これにより、ジョブとメインスクリプト間で情報を安全に共有できる。

Write-Host "2. 同期Dictionaryを作成しています..." -ForegroundColor Yellow
$syncDict = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
$syncDict["Input"] = $null
$syncDict["Output"] = $null
$syncDict["Exit"] = $false
Write-Host "   同期Dictionaryが作成されました。" -ForegroundColor Green
  • ConcurrentDictionary: スレッドセーフな辞書型コレクション。
  • syncDict["Input"]syncDict["Output"]syncDict["Exit"]: ジョブとメインスクリプト間で情報を共有するためのキー。

3. エコージョブの作成と開始

エコージョブのスクリプトブロックを作成し、バックグラウンドジョブとして実行する。

$scriptBlock = {
    param($syncDict)
    while (-not $syncDict["Exit"]) {
        if ($syncDict["Input"] -ne $null) {
            $syncDict["Output"] = $syncDict["Input"]
            $syncDict["Input"] = $null
        }
        Start-Sleep -Milliseconds 100
    }
}
$powershell = [powershell]::Create().AddScript($scriptBlock).AddArgument($syncDict)
$powershell.RunspacePool = $runspacePool
$handle = $powershell.BeginInvoke()
Write-Host "エコージョブが開始されました。入力を待っています..." -ForegroundColor Green
  • スクリプトブロック: バックグラウンドジョブとして実行されるコード。
  • BeginInvoke(): ジョブを非同期で開始。

4. ユーザー入力の受付とジョブとの通信

ユーザーからの入力を受け付け、ジョブに渡してその出力を表示する。

while (-not $syncDict["Exit"]) {
    $input = Read-Host "入力してください('exit'で終了)"
    if ($input -eq 'exit') {
        $syncDict["Exit"] = $true
        break
    }
    $syncDict["Input"] = $input
    while ($syncDict["Output"] -eq $null) {
        Start-Sleep -Milliseconds 100
    }
    Write-Host "エコー: $($syncDict["Output"])" -ForegroundColor Yellow
    $syncDict["Output"] = $null
}
  • ユーザー入力の受付Read-Hostでユーザーからの入力を受け付ける。
  • ジョブとの通信syncDictを通じてジョブに入力を渡し、出力を受け取る。

5. 終了処理とリソースのクリーンアップ

スクリプトの終了時にリソースを解放する。

Write-Host "スクリプトを終了しています..." -ForegroundColor Magenta
$powershell.EndInvoke($handle)
$powershell.Dispose()
$runspacePool.Close()
$runspacePool.Dispose()
Write-Host "スクリプトが正常に終了しました。" -ForegroundColor Green
  • リソースのクリーンアップDispose()メソッドでリソースを解放する。

まとめ

このスクリプトは、PowerShellで非同期処理を実現するための基本的な方法を示している。RunspaceとConcurrentDictionaryを活用することで、効率的かつ安全に複数のタスクを同時に処理することができる。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました