【问题标题】:Wait for multiple applications run asynchronously from batch file to finish等待多个应用程序从批处理文件异步运行完成
【发布时间】:2013-09-16 11:59:28
【问题描述】:

有一个运行多个应用程序实例的简单 Windows 批处理文件:

start app.exe param1
start app.exe param2

有没有办法同时异步运行它们(上面确实如此)并等待它们都完成以执行其他操作 - 类似于 C#

Task.WhenAll(tasksList.ToArray());
/* Process tasksList.Result */


/wait 开关在这里没有帮助,如果特定实例仍在运行,可能会进行一些轮询。

【问题讨论】:

标签: batch-file wait multiple-instances


【解决方案1】:

根据@dbenham 的回答进行调整,这就是我如何使它在for 中工作并用于无限数量的进程:

setlocal enabledelayedexpansion
for %%a in (*.*) do start "" 9>"%temp%/wait!random!.lock" /b /low "myprogram.exe" -program_parameters

:wait
ping /n 2 ::1 > nul
echo waiting processes to finish...
2>nul del "%temp%\wait*.lock" > nul
if exist "%temp%\wait*.lock" goto :wait

... more commands ...

这里%random% 不起作用,因为在调用for 时它会扩展,因此使所有数字都相同。所以我enabledelayedexpansion 并使用!random!

在循环中,我尝试删除所有文件。 2>nul 将确保屏幕上不会显示任何错误。只有在可以全部删除时才会通过(if exist)。

【讨论】:

  • 因为保证所有文件名都是唯一的,所以可以省略 RANDOM 变量的使用。锁定文件可以使用文件名唯一命名。 9>"%temp%/wait_%~a.lock"
  • 对不起,我滑了一个百分点。应该是9>"%temp%/wait_%%~a.lock"
【解决方案2】:

在单独的批处理文件中asynchBatch.bat 放:

start app.exe param1
start app.exe param2

然后在调用者批处理文件中写入:

call asynchBatch.bat
other executions
...

只有在 app.exe param1 和 app.exe param2 都完成后才会开始其他执行。

【讨论】:

    【解决方案3】:

    Powershell 有更复杂的方法来执行此操作,而无需等待循环。您可以使用 powershell 包装或调用您的脚本,甚至可以实现您喜欢的托管解决方案,以便完全按照您在 C# 中执行的操作。

    【讨论】:

      【解决方案4】:

      我想这个问题与Waiting for parallel batch scripts 略有不同,因为此应用程序正在等待 .exe 进程完成而不是批处理脚本。但解决方案几乎相同。

      您必须在您的主批处理脚本中实例化某种形式的轮询。您可以通过重定向有效地创建锁定文件。锁定文件保持锁定状态,直到进程终止。您的批处理脚本会轮询,检查它是否可以打开所有锁定文件。一旦成功,它就知道所有的进程都结束了。

      以下解决方案的唯一显着区别是START 直接启动.exe,而不是通过CMD /C 启动批处理。我还了解到(call ) 是一种非常快速的方法,可以有效地执行始终成功的无操作。所以我用(call )代替rem

      @echo off
      setlocal
      set "lock=%temp%\wait%random%.lock"
      
      :: Launch processes asynchronously, with stream 9 redirected to a lock file.
      :: The lock file will remain locked until the script ends.
      start "" 9>"%lock%1" notepad.exe
      start "" 9>"%lock%2" notepad.exe
      
      :Wait for both processes to finish (wait until lock files are no longer locked)
      1>nul 2>nul ping /n 2 ::1
      for %%N in (1 2) do (
        (call ) 9>"%lock%%%N" || goto :Wait
      ) 2>nul
      
      ::delete the lock files
      del "%lock%*"
      
      :: Finish up
      echo Done - ready to continue processing
      

      请参阅Parallel execution of shell processes,了解锁技术的一个相当复杂的应用,该技术调节最大并行进程数,并能够通过PSEXEC 将进程定向到特定的 CPU 或机器。该答案还对锁定文件技术的工作原理提供了更完整的解释。


      编辑

      可以修改等待循环,以便在添加更多进程时不需要更改:

      :Wait for all processes to finish (wait until lock files are no longer locked)
      1>nul 2>nul ping /n 2 ::1
      for %%F in ("%lock%*") do (
        (call ) 9>"%%F" || goto :Wait
      ) 2>nul
      

      【讨论】:

      • 这就是我真正想要的。要执行更多命令,我需要 1) 添加另一个 start 命令 2) 修改行 1>nul 2>nul 3>nul ping /n 3 3) 为 for %%N in (1 2 3) 添加新索引 4) 在循环结束时将 2>nul 替换为 3>nul,对吗?
      • @Crow 1) 和 3) 是的。 2) 和 4) 没有。 > 字符是重定向运算符。 1>nul 禁用标准输出。 2>nul 禁用标准错误输出。它们必须保持不变。 PING 命令是一种在不消耗 CPU 资源的情况下引入约 1 秒延迟的 hack。它可以用>nul timeout 1 /nobreak 代替,除了一些老机器没有这个命令。
      • @Crow - 我更新了答案以显示如何修改等待循环,以便在添加新进程时不需要更改。
      • 谢谢,所有这些脚本乍一看就像纯粹的魔法。
      • 是的,是的!我看到了。谢谢。
      【解决方案5】:

      您要启动同一个 app.exe 的多个实例?

      • 全部启动
      • 循环 tasklist |find "app.exe" 直到 %errorlevel%1
      • 继续您的脚本

      【讨论】:

      • @jave.web: 是的,每个没有等待周期的循环(可能是sleeptimeoutping 或任何其他需要一些时间而不消耗 CPU 时间的命令)是性能杀手。我的回答并不是“准备使用代码”(显然......),而是“操作方法”。
      【解决方案6】:

      基本上,您使用START 命令是正确的,因为它是为您现在需要的而设计的。

      另外,我建议你参考这个很棒的答案:https://stackoverflow.com/a/1449192/952310

      更新:

      要等待每个程序完成,请使用 /W 开关,查看:

      start /w app.exe param1
      start /w app.exe param2
      

      【讨论】:

      • 看到了。第一部分 - 运行实例 - 没问题,但在所有结果完成后如何处理结果对我来说仍然不是很清楚。
      • 不适用。 /w 将按顺序运行每个实例(运行 1,等待它完成,运行 2)。我需要并且我认为很清楚的是(run1,run2,等待他们都完成,做后期操作)。
      猜你喜欢
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 2016-08-17
      • 2014-01-12
      相关资源
      最近更新 更多