【问题标题】:Waiting for eight parallel batch scripts等待八个并行批处理脚本
【发布时间】:2019-07-23 19:03:13
【问题描述】:

我在编写批处理文件方面的经验为零,实际上我指的是较早的帖子 “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”窗口会打开大约 5 秒钟,然后关闭并启动另一个程序,该程序正在执行 max 的实际计算工作. 3小时。我查看了任务管理器,结果是,启动了 3 个进程。 20 秒后的“standard.exe”和“eliT_DriverLM.exe”,5 秒后的“python.exe”。由于当这 3 个进程不再运行时(不再显示在任务管理器中),该进程就完成了,程序应该至少等待“standard.exe”终止。

【问题讨论】:

  • 那么,到目前为止,您为实现目标做了哪些尝试?请edit您的问题并提供minimal reproducible example您的尝试!
  • 两个异步调用start "" cmd /c 9>"%lock%1" one.batstart "" cmd /c 9>"%lock%2" two.bat;只需编写 8 行此语法模式即可。此外,还有一个等到两个锁定文件不再锁定的代码sn-p。要等到 八个 锁定文件不再被锁定,请使用 for %%N in (1 2 3 4 5 6 7 8) do (...
  • Relatedpossible duplicate 使用另一种方法。

标签: batch-file locking


【解决方案1】:
@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 的内容是,对于我的演示,

工作 1 | q57071663_sub.bat 12
工作 2 | q57071663_sub.bat 4
工作 3 | q57071663_sub.bat 15
工作 4 | q57071663_sub.bat 2
工作 5 | q57071663_sub.bat
工作 6 | q57071663_sub.bat
工作 7 | q57071663_sub.bat
工作 8 | q57071663_sub.bat
工作 9 | q57071663_sub.bat 6
工作11 | q57071663_sub.bat 12
工作12 | q57071663_sub.bat 4
工作13 | q57071663_sub.bat 15
工作14 | q57071663_sub.bat 2
工作15 | q57071663_sub.bat
工作16 | q57071663_sub.bat
工作17 | q57071663_sub.bat
工作18 | q57071663_sub.bat
工作19 | 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 作业。


根据现在包含的 cmets 和关键信息完成修订。

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

@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 的文件,其中包含与上述相同的作业数据,除了删除了作业名称和分隔符。

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

所以 - 将每一行工作指令读到%%a,然后再读到jobinstr,然后调用子程序SUB

sub 中要做的第一件事是等待 30 秒(我的测试用了 6 秒)——这只是为了确保最后开始的作业已经创建了它的 standard.exe 实例

然后计算活动的standard.exe 实例。我已经注释掉了standard.exe 的行并留在了我的测试命令中,这要求cmd.exeq57071663 在同一tasklist 行上以指示感兴趣的实例。

如果有所需数量的实例已经处于活动状态,请延迟 1 秒,然后重试。

否则,启动所需的作业。

【讨论】:

  • 好吧,我想我忘了提一些事情。当执行批处理文件(或作业)时,“cmd”窗口会打开 5 秒,然后关闭并启动另一个程序,该程序正在执行最大计算的实际工作。 3小时。我查看了任务管理器,结果是,启动了 3 个进程。 20 秒后的“standard.exe”和“eliT_DriverLM.exe”,5 秒后的“python.exe”。由于当这 3 个进程不再运行时进程已完成,有没有办法更改您的代码,以便在延迟一段时间后检查“python.exe”?
  • @Kuba:这是关键信息,应该在问题本身中。
  • 关键问题是检测进程的终止。有没有办法明确识别与启动它们的批次相关的三个辅助过程? python 进程是否总是作为三个中的最后一个终止?
  • @Stephan 你完全正确我编辑了我的问题,感谢提及。
  • @Magoo 据我所知,它们都同时终止。问题是“python.exe”首先启动(大约 5 秒后),但“standard.exe”(大约 20 秒后启动)是 RAM 使用率最高的实际进程。据我所知,“standard.exe”是运行计算的实际程序。所以我希望程序只能同时运行八个“standard.exe”,因为计算机无法处理更多。
猜你喜欢
  • 2012-09-16
  • 2017-11-22
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多