単一スレッドの限界を突破せよ:VBScriptを用いたAutoCAD並列変換アーキテクチャの極意
AutoCADの自動化に取り組むエンジニアが必ず直面する、逃れられない「壁」がある。それは、VBA(Visual Basic for Applications)がシングルスレッド・モデルであるという事実だ。
大量のDWGファイルを、旧バージョン(例:2013形式)から新バージョン(例:2018形式)へ、あるいはその逆へと一括変換する業務を想像してほしい。1ファイルに10秒かかる処理を、1,000ファイルに対して直列(シーケンシャル)に実行すれば、それだけで約2.7時間。業務時間の大半を、ただプログレスバーを眺めるだけの無益な時間に費やすことになる。
「VBAでループを回せばいい」――そんな思考停止した設計は、プロフェッショナルの仕事ではない。我々が目指すべきは、「複数のAutoCADインスタンスを並列に制御し、マシンのリソースを限界まで使い切る並列処理アーキテクチャ」の構築である。
本稿では、VBAの限界を外部から突破するための、VBScriptを用いたオーケストレーション手法を詳解する。
1. アーキテクチャ設計:なぜVBScriptなのか?
VBA単体では、自身のプロセス内で新しいスレッドを生成することは不可能だ。そこで、AutoCADの外側に「指揮官(Orchestrator)」を配置する必要がある。
ここでVBScriptを選択する理由は、その軽量性とCOM(Component Object Model)への親和性にある。PythonやC#も有力な候補だが、追加のランタイムインストールが制限される企業の業務環境において、Windows標準のVBScriptは、最も「堅牢かつポータブルな解決策」となる。
設計コンセプト:Orchestrator-Workerパターン
1. Orchestrator (VBScript): タスクリスト(変換対象ファイル一覧)を読み込み、利用可能なCPUリソースに基づき、複数のAutoCADインスタンス(Worker)を起動・管理する。
2. Worker (AutoCAD Instance): 各インスタンスは独立したメモリ空間を持ち、与えられた単一のタスク(ファイルのオープン $\to$ バージョン変換 $\to$ 保存 $\to$ 終了)を完結させる。
3. Task Queue (CSV/Database): どのファイルが処理済みで、どれが未処理かを管理し、プロセスの中断・再開を可能にする。
2. 実装:並列変換エンジン(VBScript)
以下に、複数のAutoCADインスタンスを立ち上げ、並列で図面変換を実行するためのプロダクションレベルのコード例を示す。ここでは、並列数を制御する「スロット制」の概念を導入している。
' ==============================================================================
' AutoCAD Parallel Conversion Engine (VBScript)
'
' 【概要】
' 複数のAutoCADインスタンスを並列に制御し、DWGのバージョン変換を高速化する。
' 【注意】
' 実行前に、変換対象のファイルリスト(task_list.csv)を用意すること。
' ==============================================================================
Option Explicit
' --- 定数定義 (AutoCADの定数はVBScriptでは参照できないため、手動定義が必要) ---
Const ACDB_OPEN = 0
Const AC_R2013 = 1 ' AutoCAD 2013形式
' ※環境に合わせて適切な定数を定義すること
' --- 設定パラメータ ---
Dim MAX_PARALLEL_INSTANCES : MAX_PARALLEL_INSTANCES = 3 ' 同時起動数(CPU/RAMに応じて調整)
Dim TASK_LIST_PATH : TASK_LIST_PATH = "C:\Automation\task_list.csv"
Dim LOG_FILE_PATH : LOG_FILE_PATH = "C:\Automation\process.log"
' --- グローバル管理変数 ---
Dim objFSO, objTaskFile
Dim arrTasks() ' タスク配列
Dim taskCount : taskCount = 0
Set objFSO = CreateObject("Scripting.FileSystemObject")
Sub Main()
LoadTasks
If taskCount = 0 Then
WScript.Echo "タスクが見つかりません。"
Exit Sub
End If
WScript.Echo "処理を開始します。並列数: " & MAX_PARALLEL_INSTANCES
Dim activeInstances : activeInstances = 0
Dim currentTaskIdx : currentTaskIdx = 0
Dim runningWorkers : Set runningWorkers = CreateObject("Scripting.Dictionary")
' メインループ:全タスクが完了するまで回す
Do While currentTaskIdx < taskCount Or runningWorkers.Count > 0
' 1. 空きスロットがあれば新しいWorkerを起動
Do While runningWorkers.Count < MAX_PARALLEL_INSTANCES And currentTaskIdx < taskCount
Dim taskPath : taskPath = arrTasks(currentTaskIdx)
Dim acadApp : Set acadApp = StartAutoCAD()
If Not acadApp Is Nothing Then
' 非同期的に処理を開始させるため、ここではインスタンスを保持
' 注:VBScript単体での完全な非同期制御は難しいため、
' 本来は各Workerを別プロセス(WScript.Run)として切り出すのが理想。
' ここでは概念を示すため、逐次処理の拡張として記述。
' ※実務では、WScript.Run を用いて「別プロセスとしてVBScriptを起動」し、
' 戻り値を待たない設計にすることで真の並列化を実現する。
ProcessTask acadApp, taskPath
runningWorkers.Add currentTaskIdx, acadApp
currentTaskIdx = currentTaskIdx + 1
Else
WScript.Echo "AutoCADの起動に失敗しました。"
Exit Do
End If
Loop
' 2. 完了したWorkerのクリーンアップ (簡易的な実装)
' 実際の実装では、プロセスIDや終了イベントを監視する
' (ここでは簡略化のため、直列的な挙動をベースとした構造を示している)
' ※究極の並列化には、以下のように「タスクを引数に持つ別スクリプト」を
' WScript.Run で複数起動する手法が最も堅牢である。
Loop
WScript.Echo "すべての処理が完了しました。"
End Sub
' --- AutoCADインスタンスの起動 ---
Function StartAutoCAD()
On Error Resume Next
Dim acadApp
Set acadApp = CreateObject("AutoCAD.Application")
If Err.Number <> 0 Then
Set StartAutoCAD = Nothing
Else
acadApp.Visible = True ' デバッグ時はTrue、本番はFalseを推奨
Set StartAutoCAD = acadApp
End If
On Error GoTo 0
End Function
' --- 図面変換のコアロジック ---
Sub ProcessTask(acadApp, filePath)
On Error Resume Next
Dim doc, savePath
savePath = objFSO.GetParentFolderName(filePath) & "\" & _
objFSO.GetBaseName(filePath) & "_converted.dwg"
Set doc = acadApp.Documents.Open(filePath)
If Err.Number = 0 Then
' SaveAs(ファイル名, バージョン)
doc.SaveAs savePath, AC_R2013
doc.Close False
WriteLog "SUCCESS: " & filePath
Else
WriteLog "ERROR: " & filePath & " (Error: " & Err.Description & ")"
doc.Close False
End If
' メモリ解放
Set doc = Nothing
On Error GoTo 0
End Sub
' --- ユーティリティ関数 ---
Sub LoadTasks()
' CSVからファイルパスを読み込む実装 (省略)
End Sub
Sub WriteLog(msg)
Dim ts : Set ts = objFSO.OpenTextFile(LOG_FILE_PATH, 8, True)
ts.WriteLine Now & " : " & msg
ts.Close
End Sub
Main
3. プロフェッショナルのための「設計の急所」
上記のコードは概念を示すためのものだが、実務で「使い物になる」ツールにするためには、以下の3点を極限まで突き詰める必要がある。
① 真の並列化:`WScript.Run` によるプロセスの分離
上記のコードをそのまま実行すると、VBScriptの性質上、一つのループ内で順次実行されてしまう。真の並列化を実現するには、「Orchestrator」が「Worker(別のVBScript)」を `WScript.Run` で引数付きで叩く設計にせよ。
' Orchestrator内での実行イメージ
WScript.Run "wscript.exe ""C:\Scripts\Worker.vbs"" """ & targetFilePath & """", 0, False
`False` を指定することで、Workerの終了を待たずに次のプロセスを起動できる。これが「マルチスレッド的アプローチ」の正体だ。
② リソース・ガバナンス(メモリとCPUの衝突)
AutoCADは非常に重いアプリケーションだ。並列数を増やしすぎると、以下の現象が発生し、システム全体がクラッシュする。
- RAMの枯渇: 1インスタンスあたり2GB消費すると仮定し、32GBのメモリでは最大12〜14プロセスが限界だ。
- レジストリ・競合: 同時に複数のAutoCADが起動すると、ユーザー設定の読み込みで競合が発生することがある。
- 対策: `MAX_PARALLEL_INSTANCES` は、計算式(`LogicalProcessors * 0.5` など)に基づき、余裕を持って設定すること。
③ ゾンビプロセスの根絶
自動化ツールにおいて最も恐ろしいのは、エラー発生時にAutoCADのプロセスだけがメモリ上に残り続ける「ゾンビプロセス」だ。
- 対策: Workerスクリプトの最後には必ず `Set acadApp = Nothing` を行い、さらにOrchestrator側で、一定時間内に終了しなかったプロセスを `taskkill` 等で強制終了する監視ロジックを組み込むこと。
4. 結論
AutoCAD VBAの単一スレッドという制約は、設計の力によって容易に打破できる。
単に「コードを書く」のではなく、「複数のプロセスをいかに調和させ、リソースを管理するか」というシステムエンジニアリングの視点を持つこと。これこそが、凡庸な自動化担当者と、伝説的なチーフアーキテクトを分かつ境界線である。
次なるステップとして、このアーキテクチャに「DB連携による進捗管理」や「エラー発生時の自動リトライ機能」を実装し、真にプロフェッショナルなプロダクションツールへと昇華させてほしい。
