windows 如何在继续执行命令之前等待所有并行运行的批处理文件完成?

06odsfpq  于 2023-11-21  发布在  Windows
关注(0)|答案(3)|浏览(270)

我有一系列的活动,应该在一系列的会议上并行运行。
每个会话将并行运行所有任务,直到并行的所有任务完成后,才会运行下一个会话。
run_all_sessions.bat->每一行都应该运行,一次运行一个,直到前一行结束run_batches_1_to_4_in_parallel.bat中的所有任务后,才应该启动下一行:

start /wait run_batches_1_to_4_in_parallel.bat session_id=1
start /wait run_batches_1_to_4_in_parallel.bat session_id=2
start /wait run_batches_1_to_4_in_parallel.bat session_id=3
start /wait run_batches_1_to_4_in_parallel.bat session_id=4

字符串
Were run_batches_1_to_4_in_parallel.bat是一个批处理文件,包含以下信息:

start "running_batch_1" batch1.bat %1
start "running_batch_2" batch2.bat %1
start "running_batch_3" batch3.bat %1
start "running_batch_4" batch4.bat %1
exit

我遇到的问题是,由于run_batches_1_to_4_in_parallel.bat中没有/wait,然后run_all_sessions.bat中的下一行运行,由于batch*.bat的执行占用了大量资源,因此阻塞了机器。
我想找到的解决方案是修改run_batches_1_to_4_in_parallel.bat,在这个意义上,我不会将控制权返回给run_all_sessions.bat,直到run_batches_1_to_4_in_parallel.bat中的所有batch*.bat都完成并返回其终止代码。需要注意的是:

  • 每个batch*.bat返回大量的stdout和stderr消息。
  • 每个batch*.bat都有不同的运行时间,我必须等待,直到所有的都完成。
  • run_batches_1_to_4_in_parallel.bat中不能添加暂停,因为run_all_sessions.bat脚本应该在没有用户交互的情况下完全运行。
  • 异步解决方案优于定期检查进度的同步解决方案,因为性能对机器至关重要。

Answer https://stackoverflow.com/a/33586872/4919040建议使用set /P "=",但预期所有batch*.bat都会在标准输出中返回大量输出,因此这种方法不可行。
回答https://stackoverflow.com/a/33585114/4919040建议检查任务列表和过滤,但我既不想按进程名称过滤,也不想定期轮询和检查进程是否已经完成。
答案https://stackoverflow.com/a/49051876/4919040没有用,因为暂停命令需要用户交互。
有人建议我对run_batches_1_to_4_in_parallel.bat使用下面的解决方案,但我担心它不能保证在batch*.bat完成后返回控件。

start "running_batch_1" batch1.bat %1
start "running_batch_2" batch2.bat %1
start "running_batch_3" batch3.bat %1
start "running_batch_4" /wait batch4.bat %1
exit

wydwbb8l

wydwbb8l1#

您已经在如何在退出前等待所有批处理文件完成?或在并行启动多个任务并在Windows中等待它们?中查看了最佳解决方案:

run_batches_1_to_4_in_parallel.bat

(
start "running_batch_1" batch1.bat %1
start "running_batch_2" batch2.bat %1
start "running_batch_3" batch3.bat %1
start "running_batch_4" batch4.bat %1
) | pause
exit

字符串
这是最简单和最有效的解决方案,因为它不消耗任何CPU时间,就像其他基于循环的解决方案一样,检查一些变化的状态。在这种情况下,等待状态是 * 事件驱动的 *,也就是说,由操作系统本身触发。
在上面的两个解决方案中给出了这种方法如何工作的解释,但也许你没有完全阅读,所以这是对所用方法的不同描述:
要弄清楚这种方法是如何工作的,关键是要理解每个start命令在一个不同的. exe窗口 * 中执行其对应的.bat文件 *。当上面的示例执行时,有五个活动的cmd.exe程序,其中四个执行其对应的批处理文件,从batch1.batbatch4.bat,在其单独的窗口中。第一个(原始)cmd.exe是执行四个start命令的一个,现在正在执行pause命令(或其他解决方案中的set /P "="命令)。正如您所看到的,没有任何其他命令在xml.exe窗口 * 中显示任何输出。当然,每一个batch?.bat文件在它们自己的单独的cmd.exe窗口中显示它们的结果。
这样,pause命令将永远不会接收字符,因此,它永远不会 * 完成 *(它永远不会因为得到一个字符而终止)。然而,当四个开始命令终止时,即当由这样的开始命令启动的四个cmd.exe进程终止时,操作系统意识到在管道的左侧没有任何 * 活动 * 进程可以 * 给予输入到等待的pause命令。因此,关闭流水线并且中止pause命令。
然而,独立于任何(冗长且令人困惑的)解释,检查此方法是否有效的最简单方法就是测试它......你已经测试过了吗?

ojsjcaue

ojsjcaue2#

我不认为有OOTB解决方案可用于此。您可以尝试通过使用简单的文件操作来模拟信号量。
每个子批次需要在启动时在定义的“信号量”文件夹中创建特定于批次的信号文件,并在完成时删除此信号文件。
主批处理在启动子批处理后需要运行一个无限循环,并检查信号量文件夹是否为空。如果信号量文件夹中至少有一个文件,则表明仍有一个子批处理处于活动状态,您需要休眠并在几秒钟后重新检查。如果信号量文件夹为空,则可以假定所有子批处理都已完成,您可以继续。

e3bfsja2

e3bfsja23#

第一种方法,使用文件来指示处理未完成,每个文件对应一个批处理文件。

if exist "batch?.bat.lock" del "batch?.bat.lock"

for /L %%N in (1,1,4) do (
    echo . > "batch%%N.LOCK"
    start "running_batch_%%N" batch%%N.bat %1
)

:Wait
if exist "batch?.bat.lock" (
   timeout /T 5
   goto :Wait
)
echo All processes are finished
EXIT /B

字符串
更改4个batchN.bat文件,以便在完成数据处理并退出时删除相应的锁文件。
另一种不使用临时文件的方法是使用WaitFor命令来发送/接收信号。batchN.bat可以在完成处理时发送信号,例如:waitfor /SI exitN调用批处理文件使用:waitfor exitN N,值为1 - 4。只有一个批处理文件,这将是一个干净快速的解决方案。
但是有了四个批处理文件,它就变得有点复杂了。现在调用者需要检查/等待四个不同的信号,但是waitfor一次只能等待一个信号。
这需要一点实验,但这是可以做到的,代码并不像我最初想象的那样丑陋!
最小代码:

for /L %%N in (1,1,4) do waitfor /SI exit%%N
for /L %%N in (1,1,4) do start "running_batch_%%N" batch%%N.bat %1
for /f "tokens=*" %%A in ('start "1" /min /b waitfor exit1 ^& start "2" /min /b waitfor exit2 ^& start "3" /min /b waitfor exit3 ^& start "4" /min /b waitfor exit4') do rem
exit /b


代码,带有一些文档和更多的信息

rem send signals to avoid waitfor conflicts
for /L %%N in (1,1,4) do waitfor /SI exit%%N
rem start the 4 batchfiles
for /L %%N in (1,1,4) do start "running_batch_%%N" batch%%N.bat %1
rem start the 4 waitfor signal
for /f "tokens=*" %%A in ('start "1" /min /b waitfor exit1 ^& start "2" /min /b waitfor exit2 ^& start "3" /min /b waitfor exit3 ^& start "4" /min /b waitfor exit4') do echo %%A

rem You can check from another command prompt that there are 4 waitfor running with: tasklist /fi "imagename eq waitfor.exe"
rem when the 4 batchfiles are finished each will have send its signal and the for-loop above will finish and report 4 lines: "SUCCESS: Signal received."

exit /b

相关问题