Дождитесь завершения асинхронного запуска нескольких приложений из пакетного файла
есть простой пакетный файл Windows, который запускает несколько экземпляров приложения:
start app.exe param1
start app.exe param2
есть ли способ запускать их асинхронно одновременно (что выше) и ждать, пока они оба закончат выполнять другие действия - что-то вроде C#
Task.WhenAll(tasksList.ToArray());
/* Process tasksList.Result */
?
/wait switch не поможет здесь, некоторые опросы, если конкретный экземпляр все еще работает, возможно.
6 ответов
Я полагаю, что этот вопрос немного отличается, чем ожидание параллельных пакетных сценариев в том, что это приложение ждет .exe-процессы для завершения вместо пакетных сценариев. Но решение почти идентично.
необходимо создать экземпляр некоторой формы опроса в главном пакетном скрипте. Вы можете эффективно создать файл блокировки с помощью перенаправления. Файл блокировки остается заблокированным до завершения процесса. Ваш пакетный скрипт опрашивает, проверяя, может ли он открыть все файл блокировки. Как только это удается, он знает, что все процессы закончились.
единственное существенное различие в решении ниже заключается в том, что START
запускает .exe непосредственно вместо запуска пакета через CMD /C
. Я также узнал, что (call )
это чрезвычайно быстрый способ эффективно выполнять no-op, который всегда удается. Поэтому я заменил (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
посмотреть параллельное выполнение процессов оболочки для довольно изощренное применение метода замка который регулирует максимальное количество параллельных процессов, с способностью сразу процессов к специфическим процессорам или машинам через 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
адаптация на @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%
не работает, потому что он расширен, когда , поэтому все числа одинаковы. Так Что Я enabledelayedexpansion
и использовать !random!
.
в цикле я пытаюсь удалить все файлы. 2>nul
убедитесь, что любая ошибка не будет отображаться на экране. Он будет проходить только тогда, когда все могут быть удалены (if exist
).
в принципе, вы делаете это правильно, используя старт потому что она предназначена для того, что вам сейчас нужно.
кроме того, я бы предложил вам сослаться на этот отличный ответ:https://stackoverflow.com/a/1449192/952310
обновление:
для ожидания завершения каждой программы используйте переключатель /W, посмотрите:
start /w app.exe param1
start /w app.exe param2
вы запускаете несколько экземпляров одного и того же приложения.exe?
- запустить их всех
- цикл
tasklist |find "app.exe"
до%errorlevel%
is1
- продолжайте свой сценарий
Powershell имеет более сложные способы сделать это без циклов ожидания. Вы можете обернуть или вызвать свои сценарии с помощью powershell и даже реализовать предпочтительные управляемые решения для этого точно так же, как вы это делаете в C#.
в отдельном пакетном файле asynchBatch.bat
поставить:
start app.exe param1
start app.exe param2
затем в пакетном файле вызывающего абонента напишите:
call asynchBatch.bat
other executions
...
другие исполнения будут запускаться только после обоих приложений.exe param1 и приложение.исполняемые параметр param2 закончить.