7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

コマンドプロンプトで大量ファイルの処理を並列でやりたい

Posted at

野暮用で大量の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"
7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?