背景
既存のexeファイルをマルチプロセスで実行したいと思い、PowerShellで実装できたので備忘のために記載します。
PowerShell 7 Preview.3というバージョンなら、ForEach-Objectの新機能である「ForEach-Object -Parallel」を使えるのですが、会社PCのPowerShellバージョンが5.1だったので、泣く泣く断念しました。
ForEach-Object -Parallelの詳細については以下サイトがとても参考になります。
[PowerShell] ForEach-Objectの新機能、ForEach-Object -Parallel について
実装
サンプルとして、指定した時間待機をした後に、メッセージダイアログを表示するexeファイルを用意しました。
batファイル
@echo off
setlocal enabledelayexpansion
powershell -ExecutionPolicy Bypass -command MultiProcess.ps1
endlocal
pause
ps1ファイル
# 非同期処理の関数
function ParallelForEach-Object
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true, Position=1)][int]$para_num, # 同時実行数
[Parameter(Mandatory=$true, Position=2)][string]$process_name, # プロセス名
[Parameter(Mandatory=$true, Position=3)][scriptblock]$process, # プロセススクリプトブロック
[scriptblock]$begin={}, # ループの一番最初に実施したい処理のスクリプトブロック(今回は未指定です)
[scriptblock]$end={}, # ループの一番最後に実施したい処理のスクリプトブロック(今回は未指定です)
[Parameter(ValueFromPipeline=$true)][psobject]$inputObject # パイプライン処理用のオブジェクト
)
begin
{
&$begin
$jobs=@()
}
process
{
$jobs | Receive-Job
while(@(Get-Process | ?{$_.ProcessName -eq $process_name})).Length -ge $para_num)
{
$jobs | Receive-Job
start-sleep -Milliseconds 100
}
$jobs += Start-Job $process -argumentList $inputObject
start-sleep -Milliseconds 2000
}
end
{
while(@(Get-Process | ?{$_.ProcessName -eq $process_name})).Length -ge 0)
{
$jobs | Receive-Job
start-sleep -Milliseconds 100
}
$jobs | Receive-Job
$jobs | remove-Job
&$end
}
}
$exePath = "c:\ConsoleApp3.exe"
$processName = [System.IO.Path]::GetFileNameWithoutExtension($exePath)
$objList = @()
# 実行するexeのパスや引数を指定する
# exeの引数として"人名"と"待機時間"を指定しています。
$list = @("Aさん","Bさん","Cさん","Dさん")
$cnt = 40
foreach($name in $list)
{
$cnt -= 5;
$objList += [PSCustomObject] @{
exe = $exePath;
args = "$name $cnt";
}
}
# 同時実行数4でexeを起動する
$objList | ParallelForEach-Object 4 $processName {
Start-Process -FilePath $args[0].exe -ArgumentList $args[0].args
}
実行結果⓵
開始時間:2022/06/09 23:14:38
35秒待機しました。ようこそAさん
終了時間:2022/06/09 23:15:13
実行結果⓶
開始時間:2022/06/09 23:14:40
30秒待機しました。ようこそBさん
終了時間:2022/06/09 23:15:10
実行結果③
開始時間:2022/06/09 23:14:43
25秒待機しました。ようこそCさん
終了時間:2022/06/09 23:15:08
実行結果④
開始時間:2022/06/09 23:14:45
20秒待機しました。ようこそDさん
終了時間:2022/06/09 23:15:05
説明
AさんからDさんの名前を表示するexeを同時実行で呼び出しています。
「Get-Process」メソッドで実行中のプロセス一覧から実行中のexeのプロセス名を確認しており、
そのプロセス名の数が「$para_num」変数で指定した数よりも少なければexeを実行するという仕組みで
同時実行数を制御しています。