16

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

start app.exe param1
start app.exe param2

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

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

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

4

6 回答 6

25

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

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

以下解决方案的唯一显着区别是START直接启动 .exe 而不是通过 .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. 该答案还对锁定文件技术的工作原理提供了更全面的解释。


编辑

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

: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
于 2013-09-12T11:09:36.473 回答
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)。

于 2016-08-04T04:16:28.693 回答
0

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

  • 全部开始
  • 循环tasklist |find "app.exe"直到%errorlevel%1
  • 继续你的脚本
于 2013-09-12T08:59:08.957 回答
0

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

于 2015-09-01T08:54:12.337 回答
0

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

start app.exe param1
start app.exe param2

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

call asynchBatch.bat
other executions
...

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

于 2015-12-05T16:16:20.060 回答
-1

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

此外,我建议您参考这个很好的答案:https ://stackoverflow.com/a/1449192/952310

更新:

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

start /w app.exe param1
start /w app.exe param2
于 2013-09-12T08:18:43.520 回答