PowerShellのジョブ関連コマンドとタスクの並列実行の解説
前置き
PowerShellでは、バックグラウンドタスクの実行や、複数のバックグラウンドタスクを並列に実行させることが簡単にできます。この記事では、PowerShellのジョブ関連コマンドを紹介し、バックグラウンドで複数のタスクを同時に実行する方法をデモを交えて紹介します。さっそく、詳しい紹介を見ていきましょう。
PowerShellでバックグラウンドタスクを実行するためのモード
PowerShellでバックグラウンドタスクを実行する際のプロセスモデルを以下の図に示します(この図はインターネットから引用しています)。
まず、Start-Job コマンドでバックグラウンドタスクを実行するなど、ユーザーと対話するコマンドを実行するための PowerShell プロセスが必要です。そのようなバックグラウンドタスクは、それぞれ新しく起動されたPowerShellプロセスで実行されます。つまり、3つのバックグラウンドタスクを同時に開始すると、4つのPowerShellプロセスが同時に実行されることになります。
ジョブ関連コマンド
はStart-Jobコマンドは、バックグラウンドで実行されるタスクを開始します。Start-Jobコマンドによって実行される各タスクのために、個別のPowerShellプロセスが作成されることに注意してください。
はStop-Jobコマンドは、実行中のバックグラウンドタスク(Start-Jobによって開始されたタスク)を停止するために使用されます。
Get-Jobコマンドは、現在のセッションのバックグラウンド・タスク・オブジェクトを取得するために使用されます。
そのWait-Jobコマンドは、現在の実行プロセスをブロックし、指定されたバックグラウンドタスクの実行が終了するのを待ちます。
そのReceive-Jobコマンドは、バックグラウンド実行タスクの実行結果を取得するために使用します。例えば、バックグラウンドタスクの終了時に、Receive-Jobを使ってタスク実行の結果を取得し、出力することができます。
は、そのRemove-Jobコマンドは、現在のセッションから完了したタスクを削除します。実行中のタスクを削除するためにRemove-Jobを使用した場合、コマンドは失敗します。この場合、最初にStop-Jobコマンドでタスクを停止してから、Remove-Jobを使用して削除する必要があります。
バックグラウンドでタスクを実行する
バックグラウンドで実行されるタスクを開始するだけで、タスクの実行結果を知る必要がなく、タスクの終了時刻も気にしない場合は、Start-Jobコマンドを使用してタスクの実行を開始すれば十分です。
> Start-Job -ScriptBlock { sleep 5 }
1つのタスクを開始し、終了を待つ
ほとんどの場合、タスクがいつ終了するかを知る必要があるので、待機中のタスクが終了するまでWait-Jobコマンドで実行プロセスをブロックすることができます。
> Start-Job -ScriptBlock { sleep 5; Write-Host "Hello world."; } | Wait-Job
注意事項 上記は、Wait-Jobコマンドでジョブのステータスが"Completed"の時に出力されるものです。
さらに一歩進んで、実行中のタスクの出力も取得したいと思います。そこで、Receive-Jobコマンドを使用する必要があります。Receive-Jobコマンドはタスクが開始された後でも実行できますが、完全な出力を得たい場合は、タスクが終了してから呼び出す必要があり、その場合はWait-Jobコマンドと一緒に使用する必要があります:.
$job = Start-Job -ScriptBlock { sleep 5; Write-Host "Hello world."; }
Wait-Job $job
Receive-Job -Job $job
上記のコードをファイル mytask.ps1 に保存し、以下のように実行します。
は
Receive-Jobコマンドは、バックグラウンドで実行しているタスクの出力を出力します。
バックグラウンドで複数のタスクを実行し、終了を待つ
Start-Jobコマンドはノンブロッキングなので、理論的には何度でも実行でき、好きなだけバックグラウンドタスクを開始することができます。1つのタスクを待つのと同様に、Wait-Jobコマンドを使用してすべてのタスクの終了を待つこともできますが、この場合、Get-Jobコマンドと組み合わせて使用する必要があります。
> Get-Job | Wait-Job
より一般的な方法は、whileループでタスクの状態をチェックし続け、すべてのタスクの状態が"Completed"になったら、すべてのタスクが実行を終了したことを意味します。
Remove-Job *
#Test timer start
$start_time = (Get-Date)
Start-Job -ScriptBlock { sleep 9; Write-Host "Hello myJob1."; } -Name "myJob1"
Start-Job -ScriptBlock { sleep 5; Write-Host "Hello myJob2."; } -Name "myJob2"
$taskCount = 2
while($taskCount -gt 0)
{
foreach($job in Get-Job)
{
$state = [string]$job.State
if($state -eq "Completed")
{
Write-Host($job.Name + " Completed")
Receive-Job $job
$taskCount--
Remove-Job $job
}
}
sleep 1
}
"All tasks have been completed"
# derive the time the task ran
(New-TimeSpan $start_time).totalseconds
上記のコードをmytask.ps1ファイルに保存して実行します。
このコードでは、各タスクに名前を付け、whileループでGet-Jobコマンドを使用してタスクの現在の状態をチェックし続けています。もしタスクのステータスが "Completed"であることがわかれば、Remove-Jobコマンドでそれを取り除き、それを取り除く前にタスクの名前と出力を表示します。
バックグラウンドタスクを実行する関数をラッピングする
ここでは、複数のタスクを並行して実行するための簡単な関数をラップしています。
function Run-Tasks
{
Param
(
$taskArr,
$parallelcount=1
)
#Test timer starts
$startTime = (Get-Date)
#Remove all existing background tasks from this session
Remove-Job *
# Use the variable $taskCount to store the number of tasks that have not yet been executed
$taskCount = $taskArr.Length
# Determine if the set number of parallel tasks exceeds the number of tasks in the current task queue
if($parallelCount -gt $taskArr.Length)
{
$parallelCount = $taskArr.Length
}
# Start the initial tasks
foreach($i in 1... $parallelCount)
{
Start-Job $taskArr[$i - 1] -Name "task$i"
}
#Tasks that start after the initial task completes
$nextIndex = $parallelCount
#keep polling the created tasks while there are still tasks in the task queue, and delete a background task when it finishes
#then take the next task from the task queue for execution, and wait for all tasks to finish executing.
while(($nextIndex -lt $taskArr.Length) -or ($taskCount -gt 0))
{
foreach($job in Get-Job)
{
$state = [string]$job.State
if($state -eq "Completed")
{
Write-Host($job.Name + " Completed with the following result:")
Receive-Job $job
Remove-Job $job
$taskCount--
if($nextIndex -lt $taskArr.Length)
{
$taskNumber = $nextIndex + 1
Start-Job $taskArr[$nextIndex] -Name "task$taskNumber"
$nextIndex++
}
}
}
sleep 1
}
"All tasks have been completed"
# derive the time the task ran
(New-TimeSpan $startTime).totalseconds
}
上記の関数は、ユーザーのタスクをバックグラウンドで実行し、すべてのタスクが終了するのを待ちます。次に、この関数を使って、いくつかのタスクを実行してみましょう。
#define 6 tasks
$task1 = {sleep 12; Write-Host "Hello myJob1."; }
$task2 = {sleep 5; Write-Host "Hello myJob2."; }
$task3 = {sleep 8; Write-Host "Hello myJob3."; }
$task4 = {sleep 3; Write-Host "Hello myJob4."; }
$task5 = {sleep 20; Write-Host "Hello myJob5."; }
$task6 = {sleep 15; Write-Host "Hello myJob6."; }
# write 6 tasks to an array as a task queue
$taskArr = $task1, $task2, $task3, $task4, $task5, $task6
#Run the tasks in the array, allowing 4 tasks to run simultaneously
Run-Tasks -taskArr $taskArr -parallelcount 4
以下は実行結果です。
概要
バックグラウンドで好きなようにタスクを実行できるのは、とても気持ちのいいものです もちろん、仕事の場合は、速く、うまく(とは言えないけど)物事を終わらせることができます。この記事では、例外処理などの重要なことは省いて、並列タスクを実行する簡単なデモを提供するだけですが、PowerShell の並列タスクの旅を始めるには十分な内容になっています。
参考にしてください。
Windows PowerShellハンズオン 第2版
Powershell。並列タスクのためのシンプルなスクリプト
関連
-
Android携帯のwifiプロキシを自動設定するPowerShellスクリプト
-
powershellで仮想マシンを作成する
-
What-ifのためのPowershellエラー処理
-
PowerShellで光学ドライブをオープン/クローズする
-
PowerShellのエラートラッピングの話
-
サーバーの接続状態を監視するためのPowershellの実装
-
PowerShellでregularとValidateSetを使用してパラメータを検証する
-
Powershell ISE 抽象構文木 プログラミング例
-
PowerShell で iso8601 形式の日付と DateTime オブジェクトを交換する例
-
PowerShell Excel、CSVの詳細紹介
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
このシステムでのスクリプトの実行を無効にするPowerShellソリューション
-
スクリプトの記述と実行のためのPowershellの実装
-
ADユーザーのパスワード属性を一括で変更するPowerShellコード
-
PowerShell は、現在のスクリプトランタイムによって消費されるメモリの動的フェッチを実装しています。
-
PowerShellで特殊記号をコンソールに出力する方法
-
PowerShellファイル同期スクリプトを共有
-
Powershellは2つのフォルダの差分を比較する
-
Powershellで定数を定義する方法
-
PowershellでWebサイトのレスポンスを確認し、実行時間を計算する例
-
Powershellは、ローカルレジストリからすべてのソフトウェア関連付けの拡張子を読み取ります。