等待八个并行批处理脚本

Waiting for eight parallel batch scripts

我对批处理文件编码的经验大约为 0,实际上我指的是一个较旧的 post “Waiting for parallel batch scripts”,以及 dbenham.

的回答
@echo off
setlocal
set "lock=%temp%\wait%random%.lock"

:: Launch one and two asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" one.bat
start "" cmd /c 9>"%lock%2" two.bat

:Wait for both scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
  ( rem
  ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

:: Launch three and four asynchronously
start "" cmd /c three.bat
start "" cmd /c four.bat

他的回答很好,但我想让他的解决方案适应 运行 而不是同时处理 2 个文件,而是同时处理 8 个文件,然后再处理 8 个文件,依此类推...

有人可以帮助我吗?

到目前为止我尝试的是这个(3 个块,每个块 8 个批处理文件)

@echo off
setlocal
set "lock=%temp%\wait%random%.lock"

:: Launch 8 files asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" one.bat
start "" cmd /c 9>"%lock%2" two.bat
start "" cmd /c 9>"%lock%3" three.bat
start "" cmd /c 9>"%lock%4" four.bat
start "" cmd /c 9>"%lock%5" five.bat
start "" cmd /c 9>"%lock%6" six.bat
start "" cmd /c 9>"%lock%7" seven.bat
start "" cmd /c 9>"%lock%8" eight.bat

:Wait for all scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2 3 4 5 6 7 8) do (
  ( rem
  ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

:: Launch 8 files asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" nine.bat
start "" cmd /c 9>"%lock%2" ten.bat
start "" cmd /c 9>"%lock%3" eleven.bat
start "" cmd /c 9>"%lock%4" twelve.bat
start "" cmd /c 9>"%lock%5" thirteen.bat
start "" cmd /c 9>"%lock%6" fourteen.bat
start "" cmd /c 9>"%lock%7" fifteen.bat
start "" cmd /c 9>"%lock%8" sixteen.bat

:Wait for all scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2 3 4 5 6 7 8) do (
  ( rem
  ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

:: Launch three and four asynchronously
start "" cmd /c seventeen.bat
start "" cmd /c eighteen.bat
start "" cmd /c nineteen.bat
start "" cmd /c twenty.bat
start "" cmd /c twenty-one.bat
start "" cmd /c twenty-two.bat
start "" cmd /c twenty-three.bat
start "" cmd /c twenty-four.bat

但是好像不太对劲。 Normaly 最多八个批处理文件块将完成。 3 小时,但我等了将近 24 小时,他似乎卡在了第一个街区......

关键信息: 当执行批处理文件(或作业)时,"cmd" window 打开大约 5 秒,然后关闭,然后另一个程序starts 正在执行最大值的实际计算工作。 3小时。我查看了任务管理器,发现启动了 3 个进程。 "standard.exe" 和 "eliT_DriverLM.exe" 大约 20 秒后,"python.exe" 5 秒后。由于当这 3 个进程不再 运行ning(不再显示在任务管理器中)时进程结束,程序应该至少等待 "standard.exe" 终止。

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q57071663.txt"
SET "lockfilename=%temp%\LOCK#_"

:: BLOCKSIZE - if positive, run in blocks of this size.
:: If negative, run max this number of parallel jobs

SET /a blocksize=-5

FOR /f "usebackqtokens=1*delims=|" %%a IN ("%filename1%") DO (
 IF "%%b"=="" (SET "jobname="&SET "jobinstr=%%a") ELSE (SET "jobname=%%a"&SET "jobinstr=%%b")
  CALL :sub
)
GOTO :EOF

:sub
SET /a absblocksize=blocksize
IF %blocksize% gtr 0 GOTO blockmode
SET /a absblocksize=-blocksize
:blockmode
FOR /L %%c IN (1,1,%absblocksize%) DO IF NOT EXIST "%lockfilename%_%%c" SET "lock=%lockfilename%_%%c"&GOTO release
:: No vacant spots, so block complete. Wait for ALL to finish
:blockwait
CALL :wait1
IF %blocksize% gtr 0 IF EXIST "%lockfilename%_*" (GOTO blockwait) ELSE (GOTO blockmode)
GOTO blockmode


:release
ECHO.>"%lock%"
START "%jobname%" CMD /c "call %jobinstr%&DEL "%lock%""

GOTO :eof

:wait1
timeout /t 1 >NUL 2>NUL
GOTO :eof

您需要更改 sourcedir 的设置以适合您的情况。该列表使用适合我的系统的设置。

我使用了一个名为 q57071663.txt 的文件,其中包含一些用于测试的虚拟数据。

%lockfile%暂时使用,是您选择的文件名。

usebackq 选项是必需的,因为我选择在源文件名周围添加引号。

q57071663.txt的内容是,为了我的演示,

Job 1 | q57071663_sub.bat 12
Job 2 | q57071663_sub.bat 4
Job 3 | q57071663_sub.bat 15
Job 4 | q57071663_sub.bat 2
Job 5 | q57071663_sub.bat
Job 6 | q57071663_sub.bat
Job 7 | q57071663_sub.bat
Job 8 | q57071663_sub.bat
Job 9 | q57071663_sub.bat 6
Job11 | q57071663_sub.bat 12
Job12 | q57071663_sub.bat 4
Job13 | q57071663_sub.bat 15
Job14 | q57071663_sub.bat 2
Job15 | q57071663_sub.bat
Job16 | q57071663_sub.bat
Job17 | q57071663_sub.bat
Job18 | q57071663_sub.bat
Job19 | q57071663_sub.bat 6

每一行都是一个可选的作业名称,一个分隔符(我选择|,显然)和start...

要执行的命令

q57071663_sub.bat就是

@ECHO OFF
SETLOCAL
SET "delay=%1"
:: IF no delay defined, random 3..19 secs
IF NOT DEFINED delay SET /a delay=3+(%RANDOM% %% 17)
timeout /t %delay% >NUL 2>NUL

即。延迟(参数)秒,如果没有提供参数则延迟 3 到 19。

至于主例程,for/f使用|分隔符将文件中的每一行分开,并将这两部分分配给jobnamejobinstr,然后执行子程序 :sub.

子例程计算blocksize 的绝对值并查找丢失的锁文件。如果发现范围内缺少锁定文件,lock 获取锁定文件名,release 设置锁定文件并启动作业,并在作业终止时附加删除锁定文件的指令。

如果没有空位,我们等待。如果 blocksize 大于 0,那么如果没有剩余的锁文件,我们可以继续下一个块,否则我们等待。如果 blocksize 是否定的,那么我们再试一次。

所以 - 如果 blocksize 为正,这将 运行 一次文件 n 中的所有作业,等待 n 的每个块是在开始下一个块之前完成。如果 blocksize 是负数,那么我们 运行 n 并行作业,当任何作业终止时开始列表中的下一个作业。这 运行 份 n 份工作一直都在。


根据问题中现在包含的评论和关键信息完成修订。

看来实际要求是 standard.exe 最多 8 个实例并行 运行ning。

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q57071663_c.txt"

SET /a blocksize=5

FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
 SET "jobinstr=%%a"
 CALL :sub
)
GOTO :EOF

:sub
:: Wait 30 secs (29 + 1) to ensure last-started job is  active
timeout /t 5 >NUL 2>NUL
:delay1
timeout /t 1 >NUL 2>NUL

:: Count #times critical .exe is in tasklist

SET /a active=0
:: FOR /f %%c IN ('tasklist^|findstr /b "standard.exe"^|find /c "standard.exe"' ) DO SET active=%%c
FOR /f %%c IN ('tasklist/v^|findstr /b "cmd.exe"^|find /c "q57071663"' ) DO SET active=%%c
ECHO %active% instances active
IF %active% geq %blocksize% GOTO delay1

START "%jobinstr%" CMD /c "call %jobinstr%"

GOTO :eof

您需要更改 sourcedir 的设置以适合您的情况。该列表使用适合我的系统的设置。

我使用了一个名为 q57071663_c.txt 的文件,其中包含与上面相同的 job-data, 除了 job-name 和分隔符被删除。

我使用了 5 的 blocksize 进行测试。在 OP 的应用程序中,替换 8

所以 - 将 job-instructions 的每一行读到 %%a 然后再读到 jobinstr 并调用子例程 SUB.

sub 中要做的第一件事是等待 30 秒(我用了 6 秒进行测试)- 这只是为了确保 last-started 作业已经创建了它的实例 standard.exe

然后计算活跃的 standard.exe 个实例。我有 commented-out standard.exe 行并留在我的测试命令中,这需要 cmd.exeq57071663 位于同一行 tasklist 以指示感兴趣的实例。

如果已激活所需数量的实例,请延迟 1 秒,然后重试。

否则,启动所需的作业。