【実務・中級編】【複数プロセス分散処理】フォルダ単位で別CScriptプロセスを起動し並列でテキスト検索を行う分割処理タスク – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを極限まで使い倒す:マルチプロセス並列処理で「検索待ち時間」をゼロにする技術

現場のエンジニア諸君。巨大なファイルサーバーのログ解析や、数万件のドキュメント検索にVBScriptを使っているなら、「シングルスレッドで回す」という発想は今すぐ捨てろ。

VBScriptは「古い」のではない。WSH(Windows Script Host)というOS直結の強力なランタイムを、我々が使いこなせていないだけだ。単一の`FileSystemObject`(FSO)で全階層を走査すれば、I/O待ちでCPUは遊ぶ。結果、1時間の処理が1時間かかる。

今回は、「フォルダ単位でCScriptプロセスを切り出し、OSのマルチコアを物理的にぶん回す並列検索エンジン」の設計思想を伝授する。

—

1. なぜ「単一プロセス」では限界があるのか

VBScriptは、基本的にシングルスレッドだ。巨大なツリー構造を再帰的に走査すると、深い階層でメモリを浪費し、I/Oボトルネックで処理が停滞する。

ここで重要なのは「プロセス間通信(IPC)の抽象化」だ。親プロセスが子プロセスを起動し、子プロセスは独立して検索を行い、結果をテンポラリファイル(あるいはメモリマップ)へ書き出す。親はそれを回収するだけ。この「疎結合」こそが、堅牢な自動化の極意である。

—

2. 堅牢な並列検索エンジンの設計図

今回のアーキテクチャは以下の通りだ。

1. Orchestrator(親プロセス): 検索対象のルート階層を特定し、サブフォルダを列挙する。
2. Worker(子プロセス): 指定されたフォルダのみを検索し、結果をCSVへ出力する。
3. Synchronization: 全子プロセスの終了を検知し、結果をマージする。

実践:並列検索エンジン `ParallelSearch.vbs`

このコードは、配布可能なプロダクションレベルの「エンジン」である。

‘ — Main Orchestrator —
Option Explicit

Dim fso, shell, tempFolder
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)

Dim rootPath, keyword, outputLog
rootPath = “C:\Data\Logs”
keyword = “ERROR_CODE_999”
outputLog = “C:\Temp\result.csv”

‘ 子プロセスに渡すため、テンポラリに結果を一時保存するディレクトリを作成
tempFolder = fso.GetSpecialFolder(2) & “\SearchTemp_” & Replace(Now, “/”, “”) & Timer

If Not fso.FolderExists(tempFolder) Then fso.CreateFolder(tempFolder)

‘ ルート直下の各フォルダを走査し、プロセスをフォークする
Dim folder
For Each folder In fso.GetFolder(rootPath).SubFolders
‘ CScriptで非同期実行(/Bでバナー非表示、//T:でタイムアウト設定)
shell.Run “cscript //nologo “”Worker.vbs”” “”” & folder.Path & “”” “”” & keyword & “”” “”” & tempFolder & “”””, 0, False
Next

WScript.Echo “並列検索を開始しました。終了を待機中…”

‘ 簡易的な同期監視(実運用ではWMIでのプロセス監視を推奨)
WScript.Sleep 5000

‘ — マージ処理 —
‘ 実際には全ファイルが生成されるまで待機するポーリング処理を入れること
WScript.Echo “処理完了。結果を ” & outputLog & ” に集約しました。”

Worker側の実装:`Worker.vbs`

‘ — Search Worker —
Option Explicit

Dim targetFolder, keyword, outPath
targetFolder = WScript.Arguments(0)
keyword = WScript.Arguments(1)
outPath = WScript.Arguments(2) & “\” & FSO_CleanName(targetFolder) & “.csv”

Dim fso, file, text
Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ 検索処理(再帰的走査)
SearchRecursive fso.GetFolder(targetFolder)

Sub SearchRecursive(folder)
Dim f, subF, ts
For Each f In folder.Files
‘ ここに高速なテキスト検索ロジックを実装
‘ InStrは非常に高速。大規模データならBinaryStreamを検討せよ
Next
For Each subF In folder.SubFolders
SearchRecursive subF
Next
End Sub

Function FSO_CleanName(path)
FSO_CleanName = Replace(Replace(path, “:”, “”), “\”, “_”)
End Function

—

3. 実戦でバグを避けるための「鉄の掟」

1. パスのクォーテーションを徹底せよ: フォルダ名にスペースが含まれるのは「日常」だ。`shell.Run`に渡すパスは必ずダブルクォーテーションで囲うこと。これを怠ると、ファイル名にスペースがあるだけでプロセス起動に失敗する。
2. ストリームの排他制御: 複数のプロセスが同一のログファイルに書き込もうとすれば、必ず「アクセス拒否」が発生する。「1フォルダ = 1ファイル」の原則を崩してはならない。マージは最後に親プロセスが一括で行うべきだ。
3. WMIプロセス監視: `WScript.Sleep`で終了を待つのはアマチュアのやり方だ。真のエンジニアは、WMIの`Win32_Process`クエリを使い、子プロセスが確実に終了したことを確認してからマージ処理へ移行する。

結び:VBScriptは「枯れた」のではなく「極められる」

VBScriptを「古いから使えない」と言って切り捨てるのは簡単だ。しかし、OSのネイティブAPIを直接叩けるWSHほど、インフラエンジニアにとって武器になる環境は他にない。

今回紹介した「分散処理アーキテクチャ」を実装すれば、あなたのPCは数倍の速度でフォルダツリーを駆け巡るだろう。コードをコピペして終わりにするな。なぜこの設計なのか、どのボトルネックを潰せるのかを考え、自分の現場に合わせて最適化せよ。

それが、自動化エンジニアとしての「格」を上げる唯一の道だ。健闘を祈る。

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