
PowerShellでも非同期処理したい
PowerShellでも非同期処理が行えるのでまとめました
同期処理 と 非同期処理
「同期処理」では、ジョブは順番に実行され1つのジョブが完了するまで次のジョブは待たされます。たとえばダウンロードやAPIの応答を待つ間、次のジョブを実行しません。
「非同期処理」は、1つのジョブを実行している間に、他のジョブを実行することができます。これにより、効率的にリソースを利用し、アプリケーションの応答性を向上させることができます。
基本形
# 開始時間の表示
Get-Date
# バックグラウンドで動かすジョブ
$function1 = {
Start-Sleep 10
return "function1終了"
}
# バックグラウンドジョブ
$job1 = Start-Job -ScriptBlock $function1
# バックグラウンドジョブ終了まで待ちます
Wait-Job $job1.id
# バックグラウンドジョブの結果を取り出す
# -Waitをつけると対象のジョブが終了するまで待機
$res1 = Receive-Job $job1 -Wait
write-host $res1
# 終了時間の表示
Get-Date
$job1 = Start-Job -ScriptBlock $function1
の部分で $function1をバックグラウンドジョブとして実行して、
最後にReceive-Jobでreturnの値を受け取っています。
これではちょっとわかりにくいので
次に2つのジョブを動かしてみます
# 開始時間の表示
Get-Date
# バックグラウンドで動かすジョブ
$function1 = {
Start-Sleep 10
write-host "function1終了"
}
function function2() {
Start-Sleep 10
write-host "function2終了"
}
# バックグラウンドジョブ
$job1 = Start-Job -ScriptBlock $function1
# 関数2を呼び出して10秒スリープ
function2
# バックグラウンドジョブ終了まで待ちます
Wait-Job $job1.id
# 終了時間の表示
Get-Date
function1とfunction2の中で10秒スリープ
この2つを同時に実行してみます。

処理時間10秒の処理を2つ走らせていますが
掛かる時間は約10秒です
スコープの確認
# 開始時間の表示
Get-Date
# バックグラウンドで動かすジョブ
$test="テスト"
$function1 = {
$test="ああああ"
write-host "バックグラウンドジョブから表示:" $test
return "function1終了"
}
# バックグラウンドジョブ
$job1 = Start-Job -ScriptBlock $function1
# バックグラウンドジョブの結果を取り出す
# -Waitをつけると対象のジョブが終了するまで待機
# -AutoRemoveJobをつけるとジョブの結果を取得した後にジョブ削除
Receive-Job $job1 -Wait -AutoRemoveJob
$test
# 終了時間の表示
Get-Date

スコープが効いているので$function1の中で変数$testの中を書き換えても外の変数$testに影響はありません。
バックグラウンドジョブの途中経過を出力する
# 開始時間の表示
Get-Date
# バックグラウンドで動かすジョブ
$function1 = {
for ($i=0;$i -lt 10;$i++){
$i
Start-Sleep 1
}
return "function1終了"
}
# バックグラウンドジョブ
$job1 = Start-Job -ScriptBlock $function1
# バックグラウンドジョブ終了までループ
while ($job1.State -ne "Completed") {
""
$job1.ChildJobs[0].Output
sleep 1
}
# 終了時間の表示
Get-Date
バックグラウンドジョブ終了までループして
$job1.ChildJobs[0].Outputで途中の出力を取り出しています。
たとえば処理の進捗状況をバー表示するときに使えますね
# バックグラウンドで動かすジョブ
$function1 = {
for ($i=0;$i -lt 10;$i++){
$i
Start-Sleep 1
}
return "function1終了"
}
# バックグラウンドジョブ
$job1 = Start-Job -ScriptBlock $function1
while ($job1.State -ne "Completed") {
$tmp=""
for($i=0;$i -lt [int]($job1.ChildJobs[0].Output[-1])+1;$i++){
$tmp+="■"
}
for($i=[int]($job1.ChildJobs[0].Output[-1])+1;$i -lt 10;$i++){
$tmp+="□"
}
$tmp
sleep 1
}

ジョブの削除
ジョブが終了しても残っているで削除しましょう。
最後に次のコマンドを入れておくと終了したジョブを全部削除することができます。
Get-Job -State Completed | Remove-Job
他の方法として
Receive-Job に
「-AutoRemoveJob」をつけるとジョブの結果を取得した後にジョブの削除します。
例:
Receive-Job $job1 -Wait -AutoRemoveJob
#PowerShell #プログラミング学習 #プログラミング入門 #非同期処理 #バックグランドジョブ #コマンドレット
非同期処理を応用した記事はこちら