野暮用で大量のSVGをinkscapeでEMFに変換しようとしたら、雑なループだと結構時間がかかりそうだったので並列して処理させたかった。ただ、メモリやプロセスを食いつぶして中途半端に止まるのは嫌なので上限数を決めたかった。
svg2emf.bat
@echo off
setlocal enabledelayedexpansion
set INKSCAPE=C:\PATH_TO_INKSCAPE\inkscape.exe
:: 並列数
set PARALLEL=10
:: この辺りは自由に書く
FOR /f "delims=" %%A in ('where /r . *.svg') do (
echo "%INKSCAPE%" "%%~A" -M "%%~dpnA.emf"
call :BACKGROUND "%INKSCAPE%" "%%~A" -M "%%~dpnA.emf"
)
:: 終了
exit /B
:: 汎用並列処理
:BACKGROUND command arg1 arg2 ...
:: バックグラウンド処理する
:: startは最初にダブルクォート付の引数にあるとタイトルとして解釈するので、空文字列を渡しておく
start /B "" %*
:: プロセスが指定数未満になるまで待機するループ
:WAIT_LOOP
for /F %%c in ('tasklist ^| find /C "%~nx1"') do set PCOUNT=%%c
if !PCOUNT! GEQ %PARALLEL% timeout 1 /nobreak >nul && goto WAIT_LOOP
exit /B
うーん、結構めんどい。
ポイント
-
FOR /f "delims=" %%A in ('where /r . *.svg') do
で1行づつ処理 -
start /B "" コマンド ...
でバックグラウンド処理- startの最初のダブルクォート付の引数はタイトルと認識されて事故る事例が多いことで有名なので、空文字列を渡して事故を回避する。
-
tasklist
でプロセス数を数えてN個以上起動しないようにする- 雑な数え方なので、変なプロセス名があるとバッティングする可能性があったり、バッチとは関係ないプロセスも数えてしまうので注意する
ただ、コマンドプロンプトの処理はアホみたいに時間がかかるので、今回のような1秒で終わるような処理をプロセス数を制限して並列処理しようとしても、プロセス数を制限しようとする処理がボトルネックになる。(自分のPCでは6個以上実行されることはなかった)
というわけで、コマンドプロンプトは並列処理に向いてないと思うので他の方法を使った方がよいでしょう。
例えば、Git for windowsを入れている環境なら、findとxargsで処理したほうが速く処理できます。
# 10並列で処理
/usr/bin/find . -name "*.svg" | xargs -P 10 -I{} /c/PATH_TO_INKSCAPE/inkscape.exe "{}" -M "{}.emf"