Начните параллельные пакеты с маской имени файла и дождитесь их завершения - PullRequest
0 голосов
/ 23 ноября 2018

Я пытаюсь запустить фиксированное количество одновременных пакетных процессов с одинаковыми именами файлов, все в одном каталоге:

TestMe1.bat
TestMe2.bat
TestMe3.bat

Все пакеты должны запускаться одновременно, и все должны завершиться допакет продолжается, например, master.bat:

echo Starting batches

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

echo All batches have stopped and we can safely continue

Я пытаюсь найти способ запустить все пакеты в каталоге, соответствующие TestMe * .bat, чтобы мне не пришлось создаватьновый файл master.bat каждый раз.Примерно так, но, знаете, работает:

echo Starting batches

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

echo All batches have stopped and we can safely continue

Спасибо , и , за то, что вы так далеко зашли.

Совети идеи с благодарностью приняты!

Ответы [ 2 ]

0 голосов
/ 24 ноября 2018

Сначала вы должны понять, как работает этот особый метод использования канала с командой pause и почему его можно использовать для ожидания нескольких параллельных процессов.

Принимая ваш первый пример рабочего кода в качестве исходногоpoint

(
start "task1" cmd /C "TestMe1.bat"
start "task2" cmd /C "TestMe2.bat"
start "task3" cmd /C "TestMe3.bat"
) | pause

Это работает, потому что каждый новый экземпляр CMD, который вызывается командой start, будет запущен в новой консоли с ее stdout и stderr, перенаправленными на эту новую консоль,поэтому выходы дочерних CMD не будут перенаправлены в канал и, следовательно, не будут использованы командой pause, ожидающей ввода из канала.

НО,

Тем не менее каждый из процессов унаследовал дескриптор канала, поэтому дескриптор канала будет оставаться открытым до тех пор, пока дочерние процессы активны.

КакКак следствие, команда pause в правой части канала будет оставаться активной, ожидая ввода с левой стороны канала, пока не получит ввод из канала (что никогда не произойдет) или все дочерние процессы не завершатся и не закроютдескриптор канала.

Таким образом, основной экземпляр CMD, который выполняет файл главного пакета, фактически ожидает завершения команды pause (правая часть канала), которая, в свою очередь, ожидает дочерние процессы.(потенциальные пишущие каналы) для завершения.

Теперь становится понятно, почему не работает ваш второй попытанный код, включающий цикл FOR.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do start "task" cmd /C "%%x"
) | pause

Команда FOR внутри каналавыполняется дочерним CMD в режиме командной строки. В этом режиме команда выводит по умолчанию , поэтому каждая команда внутритело FOR будет передано на стандартный вывод (канал) перед выполнением, которое, в свою очередь, передает команду pause и завершает свой процесс до того, как будет создан даже первый дочерний процесс. Поэтому выполнение пакетного файла продолжается, даже не ожидаядочерний процесс завершается.

Эту проблему можно легко решить, поставив @ после того, как do выключит эхо-команду внутри тела FOR.

(
for /f "delims=" %%x in ('dir /b /a-d TestMe*.bat') do @start "task" cmd /C "%%x"
) | pause>nul

Youможет также захотеть скрыть вывод команды pause, перенаправив ее на nul

0 голосов
/ 24 ноября 2018

РЕДАКТИРОВАТЬ: Кажется, я пропустил суть этого вопроса.Несмотря на это, я думаю, я все равно оставлю это здесь для других людей, чтобы найти.Не стесняйтесь, однако, понизить.


Вот другие предложения по ожиданию завершения подчиненных процессов.

Ваш основной процесс должен периодически проверять, выполнены ли все подчиненные процессы.Существует множество способов сделать это.Я назову несколько:

Перед этим, пожалуйста, вставьте задержку между проверками, чтобы не использовать весь ЦП в узком цикле, как это:

timeout /t 1 /nobreak

Маркерные файлы

Заставить подчиненные процессы создать или удалить файл, когда они собираются завершить

Вы можете создавать файлы следующим образом:

echo ANYTHING>FILENAME

Главный сценарий должен периодически проверять, существуют ли эти файлы следующим образом:

if exist FILENAME goto IT_EXISTS

Когда все / ни один из файлов не существует, ваша задача выполнена.

Чтобы предотвратить беспорядок, создайте файлы в папке %random% внутри каталога %temp% и передайте его имя подчиненнымс помощью аргументов %1, %2 ...

Проверьте наличие процесса по заголовку окна

Запустите tasklist и проанализируйте его выходные данные, чтобы определить, все ли выполняются подчиненные программы.

Вероятно, самый простой способ - использовать имя окна, чтобы отфильтровать "ваши" процессы.

Запустите их так:

start "WINDOW_TITLE" "BATCH_FILE" ARGUMENTS

, затем найдите их так:

TASKLIST /fi "Windowtitle eq WINDOW_TITLE" | find ".exe"
if "%errorlevel%" == "0" goto PROCESS_EXISTS

если ничего не найдено, ваша задача оконченад.

Дополнительную информацию можно найти по адресу: A , B , C

Проверка наличия процесса с помощью PID

Вместо заголовка окна вы можете использовать PID процессов.

Чтобы получить его, запустите ваш процесс с WMIC, как описано здесь

Внешние программы

Вы можете загрузить или написать внешнюю программу для облегчения межпроцессного взаимодействия.Примеры включают:

  • TCP-сервер и клиенты с netcat
  • Используйте mkfifo из GnuWin32 coreutils, чтобы создать именованный канал и использовать его
  • Семафоры Windows исобытия через пользовательскую программу C / C # / AutoIT
  • Утилиты, такие как NirCmd и PsExec, могут упростить процедуру проверки PID

.... и более

Если ни одно из решений не работает для вас, отредактируйте вопрос, чтобы сузить свой запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...