【入門編】【疑似マルチスレッド】WScript.Shell.Exec を並列起動して複数タスクを並行処理するタスクランナーの構築 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

こんにちは! VBScriptの世界へようこそ。
普段、Excelのマクロ(VBA)やバッチファイルを書いていると、ふと思うことありませんか?

「いくつかの重たい処理を、順番にじゃなくて同時に実行できたら、終わるのが何倍も早くなるのになぁ……」と。

実は、VBScript(そしてそれを動かすWSH環境)は、デフォルトでは「完全なシングルスレッド(一本道)」です。一つの処理が終わるまで、次の処理に進むことはできません。

しかし! 伝説のチーフアーキテクトである私から、現場で今すぐ使える「WScript.Shell.Execを用いた疑似マルチスレッド・タスクランナー」の極意を伝授しましょう。ここをクリアすれば、あなたのVBScriptのスキルは一気にプロの領域へと駆け上がりますよ。

—

なぜVBScriptで「並列処理」が必要なのか?

通常、`WScript.Shell` の `Run` メソッドを使うと、外部プログラムや別スクリプトを起動できますが、デフォルトでは「その処理が終わるまでVBScript全体の実行が一時停止」してしまいます。

これを無理に並列っぽくやろうとすると、昔ながらのバッチファイルで `start /b` を乱発して管理不能になるのがオチです。

そこで登場するのが `Exec` メソッド です。
`Exec` は、起動したプロセス(仕事の担当者)のオブジェクトを返してくれます。このオブジェクトが持つ `.Status`(現在の状態)や `.StdOut`(標準出力)を監視することで、「複数の部下に同時に仕事を投げ、全員が『終わりました!』と報告してくるのをスマートに待つ」というタスクランナーが作れるのです。

—

本日のゴール:疑似マルチスレッド・タスクランナーの全貌

今回は、3つの「時間のかかるダミー処理(または外部コマンド)」を同時に起動し、すべての処理が完了するのを監視・待機する実用スクリプトを作成します。

以下のコードをメモ帳に貼り付け、拡張子を `.vbs` (例: `task_runner.vbs`)にして保存してください。

‘ ==============================================================================
‘ スクリプト名: ParallelTaskRunner.vbs
‘ 概要: WScript.Shell.Exec を使った疑似マルチスレッド・タスクランナー
‘ ==============================================================================

Option Explicit

Sub Main()
Dim objShell
Set objShell = CreateObject(“WScript.Shell”)

WScript.Echo “=== 疑似マルチスレッド・タスクランナーを開始します ===”
Dim startTime
startTime = Timer

‘ 1. 並列実行したいタスク(コマンドやスクリプト)の配列を定義
‘ ここでは Windows標準の ping や timeout コマンドをダミーとして使います
Dim tasks(2)
tasks(0) = “cmd.exe /c timeout /t 3” ‘ 3秒待つタスク
tasks(1) = “cmd.exe /c timeout /t 5” ‘ 5秒待つタスク
tasks(2) = “cmd.exe /c timeout /t 2” ‘ 2秒待つタスク

Dim UBoundTasks
UBoundTasks = UBound(tasks)

‘ プロセスオブジェクトを格納する配列
Dim execObjs()
ReDim execObjs(UBoundTasks)

Dim i

‘ 2. 全タスクを「同時に」バックグラウンド起動(スレッドの生成に相当)
For i = 0 To UBoundTasks
WScript.Echo “[” & FormatTime() & “] タスク ” & i & ” を起動: ” & tasks(i)
‘ Execメソッドはプロセスを非同期(バックグラウンド)で走らせる
Set execObjs(i) = objShell.Exec(tasks(i))
Next

WScript.Echo “[” & FormatTime() & “] すべてのタスクの起動完了。全終了を監視します…”
WScript.Echo “————————————————–”

‘ 3. 全プロセスの終了を監視するループ(ポーリング処理)
Dim allFinished
Do
allFinished = True ‘ いったん全員終わったと仮定

For i = 0 To UBoundTasks
‘ Status が 0 でなければ(まだ動いているなら)
If execObjs(i).Status = 0 Then
allFinished = False ‘ まだ終わっていないやつがいた!
End If
Next

If Not allFinished Then
‘ CPUを焼き切らせない(高負荷を防ぐ)ための極めて重要な配慮
WScript.Sleep 200 ‘ 0.2秒インターバル
End If

Loop Until allFinished ‘ 全員が終わるまでループし続ける

Dim totalTime
totalTime = Round(Timer – startTime, 2)

WScript.Echo “————————————————–”
WScript.Echo “[” & FormatTime() & “] すべてのタスクが正常に終了しました!”
WScript.Echo “総実行時間: ” & totalTime & ” 秒”

‘ もし順番に実行していたら (3 + 5 + 2) = 10秒 かかるはずが、
‘ 並列実行なら一番長いタスクの「約5秒」で終わるはずです!

Set objShell = Nothing
End Sub

‘ ログ用に見やすい現在時刻を返す関数
Function FormatTime()
FormatTime = Right(“0” & Hour(Now), 2) & “:” & _
Right(“0” & Minute(Now), 2) & “:” & _
Right(“0” & Second(Now), 2)
End Function

‘ メイン処理の実行
Main()

—

コードの核心:ここがプロの技術

初心者の方が「おっ」と驚き、かつ現場で絶対に押さえておくべきポイントを3つ解説します。

1. `Exec` と `Run` の決定的な違い

  • `Run` メソッド: 窓口が一つしかない銀行の窓口のようなもの。処理が終わるまで次の番号札を呼べません。
  • `Exec` メソッド: ドライブスルーの受取口を複数作るようなもの。注文(起動)したら、料理ができあがるのを待たずに次の車の注文を受け付けられます。

2. ループを回すときの命綱: `WScript.Sleep 200`

監視ループ(`Do … Loop Until`)の中で、何の配慮もせずに状態チェックを回し続けると、PCのCPU使用率が片側コア100%に張り付いてパソコンが爆音を立て始めます(ビジーウェイトと呼ばれるアンチパターンです)。
`WScript.Sleep 200` を挟むことで、「0.2秒に1回だけ軽く生存確認して、あとはCPUを休ませる」という優しいエンジニアリングが成立します。

3. マジックナンバーの正体: `.Status`

`Exec` で返されるオブジェクトには `.Status` プロパティがあります。

  • `0`: `WScript.WshRunning`(実行中)
  • `1`: `WScript.WshFinished`(終了)

これを利用して、「1つでも `0`(実行中)のやつがいたら、`allFinished` フラグを `False` に戻して粘る」というロジックを組んでいます。

—

陥りやすいエラーと現場の罠

現場でこのスクリプトを応用する際、以下の罠にハマることがよくあります。

  • 罠1: 画面(コマンドプロンプト)の黒い窓がいっぱい出る
  • `WScript.Shell.Exec` は、バッチファイルやCUIツールを叩くときにデフォルトで黒いウィンドウを表示します。もしバックグラウンドで完全に隠したい場合は、`Exec` ではなく `Run` との組み合わせや、VBScriptの実行ランタイム(`wscript.exe` で実行する)を意識する必要がありますが、基本的にはウィンドウが表示されても仕様です。
  • 罠2: パスにスペースが含まれているときの構文エラー
  • `execObjs(i) = objShell.Exec(“C:\My Folder\tool.exe”)` のように、フォルダ名にスペースがある場合はダブルクォーテーションのエスケープが必要です。
  • `execObjs(i) = objShell.Exec(“””C:\My Folder\tool.exe”””)` のように、二重引用符を重ねて渡すのがVBScriptの鉄則です。

—

まとめ:ここをクリアすればVBScriptの基本はバッチリ!

いかがでしょうか? 単なる「上から下へ流すだけのコード」から脱却し、オブジェクトの状態を監視して制御する(ポーリング処理)という概念を手に入れました。

このタスクランナーの技術をベースにすれば、

  • 大量のCSVファイルを一斉に別スクリプトで変換する
  • 複数のWebスクレイピング用スクリプトを同時に走らせて時短する

といった、業務効率化の強力な武器になります。

「VBScriptなんて古い」と言う人もいますが、OS標準で追加インストールなしで動き、こうしたプロセス制御までサラッと書ける点において、今なおWindows環境の裏側で最強の黒衣(くろご)であることに変わりはありません。

ぜひあなたの現場でも試してみてくださいね。それでは、次のステップでお会いしましょう!

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