Пакетная остановка Программа A при запуске программы B, Запуск программы A при завершении программы B - PullRequest
0 голосов
/ 12 ноября 2018

Я синхронизирую свои документы с помощью программы Google для синхронизации. Однако я не хочу, чтобы программа синхронизации вмешивалась в мои файлы проекта, когда у меня открыты определенные программы. Моя попытка решения ниже.

Это действительно неуклюжий способ попытаться выключить программу A при запуске программы B, а затем снова включить программу A, когда программа B остановится. Пакетный скрипт ниже делает это эффективно, но он занимает значительную часть процессорной мощности (от 1 до 4% на моем мобильном i5 8-го поколения). Есть ли более элегантный способ сделать это? Я готов рассмотреть другие инструменты (например, AutoIT).

РЕДАКТИРОВАТЬ, согласно предложению, в конце я добавил простой 15-секундный тайм-аут, что делает эту программу приемлемо интенсивно использующей процессор (то есть, нет). Запуск через планировщик задач как скрытый делает это рабочим решением.

@echo off
rem mutually exclusive program enforcer

rem initialize variables
set gDriveOn=init
set reaperOn=init

rem begin infinite loop for monitoring on states
:loopStart

    tasklist /FI "IMAGENAME eq reaper.exe" 2>NUL | find /I /N "reaper.exe">NUL
if "%ERRORLEVEL%"=="0" (
    set reaperOn="TRUE" 
    goto gDrivecheck
    )

rem else if reaper not found
set reaperOn="FALSE"

:gDriveCheck    
    tasklist /FI "IMAGENAME eq googledrivesync.exe" 2>NUL | find /I /N "googledrivesync.exe">NUL
if "%ERRORLEVEL%"=="0" (
    set gDriveOn="TRUE" 
    goto doStuff
    )

rem else if Google Drive not found
set gDriveOn="FALSE"

:doStuff
rem turn off gdrive when reaper is on
if %reaperOn% == "TRUE" (
    if %gDriveOn% == "TRUE" (
        taskkill /f /t /im googledrivesync.exe
        )
    )

if %reaperOn% == "FALSE" (
    if %gDriveOn% == "FALSE" (
        start  C:\"Program Files"\Google\Drive\googledrivesync.exe
        )
    )

rem delay 15 seconds for efficiency
timeout 15
goto :loopStart
)
rem end of infinite loop
)

1 Ответ

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

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

Что касается производительности:

Задержка пакетного файла

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

Это, в основном, предписывает вашему компьютеру использовать всю доступную вычислительную мощность для проверки существования процесса. Эта программа теоретически должна использовать процессор на 100%, но, поскольку по какой-то причине перечисление задач в Windows медленное и неэффективное, и, вероятно, у вас более одного ядра ЦП, а пакетная обработка сама по себе медленная, она может использовать только часть ЦП. .

Скорее всего, вам не нужно часто проверять процессы. Обычно это делается один раз в 1-10 секунд. Если это приемлемо, вставьте задержку где-нибудь в коде так:

TIMEOUT /T 5 /NOBREAK

где 5 - секунды ожидания. См. timeout /? или это для получения дополнительной информации.

AutoIT

В AutoIt вам потребуется ProcessExists() для проверки существования процесса и Sleep() для вставки задержки. Уничтожение процесса выполняется с помощью ProcessClose() и Run() запускает его. Документация доступна здесь под Function Reference

Проверка процессов в Windows все еще медленная и неэффективная. Документация AutoIT предполагает, что the process is polled approximately every 250 milliseconds, что, вероятно, означает, что если вы попытаетесь запросить его еще быстрее, вы получите результаты, сохраненные в последний раз, поэтому имеет смысл вставить Sleep(250) или более.

Однако это в основном относится к запросу процесса по имени, который запрашивает список всех запущенных процессов и ищет в нем ваш. Этого не нужно делать, если вы знаете, что процесс уже существует - вы можете просто использовать его идентификатор процесса (PID), чтобы проверить, остановился ли он - что должно быть быстрее. Поэтому вместо ProcessExists("notepad.exe") вы можете сделать что-то вроде этого:

local $pid = 0
while true
  if ($pid <> 0) then $pid = ProcessExists($pid) ;Process already existed, use PID
  if ($pid = 0) then $pid = ProcessExists("notepad.exe") ;Process did not exist
  if ($pid <> 0) then 
       ;do something if process exists...
  endif
  sleep(300)
  .........
wend

Это работает, потому что ProcessExists() возвращает PID, если процесс существует, или 0, если нет. Первая строка if запускается, если $pid уже было известно с момента последней проверки. Если этого не было или если мы никогда не проверяли ранее или если это было, но больше не существует, тогда запускается вторая строка и выполняет проверку на основе имени процесса. Это должно быть повторено для второго процесса. Обратите внимание, что это преднамеренно не if-then-else, потому что 1-я проверка может установить $pid на 0.

EXE замена

Если приведенные выше решения не работают - например, из-за того, что reaper.exe просто ужасно падает, если случается попытка получить доступ к чему-то, что googledrivesync.exe удерживает - тогда, вероятно, следует сделать что-то еще.

Один из вариантов - переименовать reaper.exe в real_reaper.exe и скомпилировать скрипт autoit в новый reaper.exe, который убивает googledrivesync и запускает real_reaper.exe. Этот скрипт должен передавать все параметры, что-то вроде

RunWait ('"real_reaper.exe" ' & $CmdLineRaw)

должен сделать трюк. Это ждет, пока real_reaper.exe завершит работу, а затем вы можете сделать Run("googledrivesync.exe")

Это может не работать должным образом, если программа, которая запускается reaper.exe, использует некоторые приемы, но в большинстве случаев должна работать.

...