1

У меня есть пакет, который запускает серию команд, которые будут долго и интенсивно использовать процессор. Я не против, когда он будет закончен, поэтому я бы предпочел, чтобы он использовал только незанятые циклы процессора. Если я установлю приоритет процесса, который запускает пакет (некоторый cmd.exe) в том же пакете, любой дочерний процесс должен наследовать его приоритет. Я знаю, что вы можете изменить приоритет процесса, используя wmic. Например:

wmic process where name="cmd.exe" CALL setpriority "idle"

действительно выполнит задание, НО также снизит любой другой запущенный экземпляр cmd.exe , что может не всегда подходить.

Есть ли способ определить, какой процесс запускает пакет, и установить ТОЛЬКО его приоритет в режим idle?

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

Это проблема, которую я иногда нахожу, но в конкретном .bat я пишу сейчас, я передаю переменное число файлов, которые должны обрабатываться по одному за раз.

3 ответа3

2

Один из подходов состоит в том, чтобы начать с поиска PID (сокращенного от "ID процесса").

Роль процесса WMIC поддерживает не только установление приоритета. Вы также можете получить подробную информацию. например, следующее (запустить в одной строке):

WMIC process where name="cmd.exe" get Caption,CommandLine,Name,ParentProcessId,ProcessId /FORMAT:LIST

(Естественно, это предназначено для запуска из традиционной командной строки, как пример из вашего вопроса. Использование PowerShell потребует дополнительного экранирования.)

Однако у вас может быть несколько копий CMD.EXE, что может вызвать проблемы. Это может быть проще, если у вас есть некоторый контроль над тем, как запускается ваш пакетный файл. Вопрос Дина StackOverflow.com, «получение идентификатора процесса exe-файла, запущенного в Bat File», предоставляет несколько решений для получения PID в переменной среды. Я предлагаю вам взглянуть на эти решения, чтобы определить, какое из них выглядит наиболее приятным для вас, но вот один из возможных подходов:

C:\> wmic Process WHERE "CommandLine LIKE '%%MyProgWMICflag%%'" Get ParentProcessID /format:list

Это должно показать вам ParentProcessID для команды WMIC, который будет PID программы, которая называется WMIC (предположительно, ваша оболочка).

Это основано на ответе foxidrive на приведенной выше гиперссылке на страницу решений о получении PID. (Этот ответ также показывает получение этого в переменную окружения, если хотите.)

Затем включите ProcessId в ваше предложение WHERE. например:

WMIC process where "name='cmd.exe' AND ProcessId='12345'" CALL setpriority "idle"

Примечание: это только один из подходов. Там могут быть некоторые другие общие черты, которые вы считаете, лучше проверить. Вы можете увидеть список доступных свойств для проверки, используя что-то вроде:
WMIC /OUTPUT:"Results.txt" Process Get /FORMAT:LIST

0

вам нужно будет запустить пакет с помощью START (из другого пакета) - тогда запуск может иметь отдельный приоритет

START "" batch.bat /B /LOW
0

Это рабочий SetMyPrio.bat MyPrio.bat который вы можете использовать от другого для установки приоритета вашего пакета. Если вы скопируете его в каталог в вашем %PATH% вы можете вызывать его в любое время, когда вам это нужно, и т.д. Как обычно. Благодаря TOOGAM, который дал мне инструменты и метод, чтобы написать это. Переменная UniqueString гарантирует, что точно определенный процесс - это именно то, что вам нужно, а не любой другой экземпляр вашего пакета (маловероятный, но возможный сценарий).

@echo off

GOTO :EndOfReminder

<HELP>

USAGE:

From any batch file or command prompt, write
   CALL MyPrio [/?|/h] [<priority>|get]
to set the priority of the caller cmd. Default for <priority> is idle.

/?, /h        This help.

<priority>    If you want your priority change to 
                 idle          -- no parameter, 64, idle or "idle"
                 below normal  -- 16384 or "below normal"
                 normal        -- 32, normal or "normal"
                 above normal  -- 32768 or "above normal"
                 high priority -- 128 or "high priority"
                 real time     -- 256, realtime or "realtime"
get           Returns current priority as errorlevel

TO DO
   - Parameter error control.
   - Support for Unicode characters in help.
</HELP>

:EndOfReminder
setlocal
set Priority=%~1

if /I ["%Priority%"]==["/h"] ( call :PrintHelp & exit /b )
if ["%Priority%"]==["/?"] ( call :PrintHelp & exit /b )

set UniqueString=%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%

if ["%Priority%"]==["get"] for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get Priority /format:LIST`) do exit /b %%a

if not defined Priority set Priority=idle
for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get ParentProcessID /format:LIST`) do set myPID=%%a
wmic process where "ProcessId='%myPID%'" CALL setpriority "%Priority%" > nul 2>&1

endlocal
goto :eof

:PrintHelp
setlocal DisableDelayedExpansion
call :eln 0
set "levelerror=^%%errorlevel^%%"
for /F "delims=" %%a in ('find /v /n "" "%~f0"') do (
   set "line=%%a"

   REM We store errorlevel in tmpel because setlocal will set errorlevel to 0...
   call set tmpel=%levelerror%
   setlocal EnableDelayedExpansion
   REM ... and now we restore it
   REM %levelerror% was expanded to %errorlevel% before running the iteration
   REM and the CALL SET allows actual errorlevel be stored in tmpel
   REM Finally, we set errorlevel again
   call :eln !tmpel!

   set "line=!line:*]=!"

   if /i "!line!"=="</HELP>" exit /b 0
   if errorlevel 1 echo(!line!
   if /i "!line!"=="<HELP>" call :eln 1
REM errorlevel is the only value that survives the following endlocal
   endlocal
)
exit /b 1

:eln
REM Sets errorlevel to %1
exit /b %1

Изменить (2018-06-12)

  • Изменили имя на MyPrio, добавили параметры /? /h и get .
  • Варианты /? и /h распечатать текст, который вы пишете в напоминании между <HELP> и </HELP> . Этот метод можно использовать в любой другой партии, которая вам нужна.

Если вы делаете вызов MyPrio.bat в начале пакета, каждый раз, когда вы запускаете его, независимо от командной строки или перетаскивания файлов из Проводника Windows (которые становятся параметрами), каждая его часть (и дочерние процессы) будет работать с вашим желаемым приоритетом.

Например:

@echo off
call MyPrio

REM Here comes a set of commands that will run with idle priority.

call MyPrio normal

REM Here may come some interactive part to request information needed to continue.

call MyPrio

REM Back to idle (or put any other priority you prefer).

call MyPrio normal

REM You may want to set the priority to normal at the end just in case you call the batch from a command line.

КОММЕНТАРИИ

Я сделал пакет с именем PrioTest.bat для тестирования MyPrio.bat с каждой возможной опцией и заказал их так, чтобы при любом вызове приоритет менялся. Я сделал подпрограмму (:test1), которая:

1. Получает текущий приоритет и сохраняет его в myPrioBefore .
2. Вызывает MyPrio с параметром теста.
3. Получает новый приоритет и сохраняет его в myPrioAfter .
4. Запускает скрытый ping -t localhost .
5. Получает приоритет и PID процесса ping и сохраняет их в pingPrio и pingPID .
6. Печатает значения myPrioBefore , вызова MyPrio , myPrioAfter и pingPrio .
7. Убивает начатый ping (будучи уверенным, что это не другой).

@echo off

setlocal

set UniqueString=%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%-%RANDOM%
for /f "usebackq tokens=2 delims==" %%a in (`wmic Process WHERE "name='cmd.exe' AND CommandLine LIKE '%%%UniqueString%%%'" Get ParentProcessID /format:LIST`) do set myPID=%%a
for %%a in (64 16384 32 32768 128 256 idle "below normal" none normal "idle" "normal" "above normal" realtime "high priority" "realtime") do call :test1 %%a
CALL MyPrio normal

endlocal
goto :eof

:test1
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "ProcessID='%%myPID%%'" Get Priority /format:LIST`) do set myPrioBefore=%%b
if [%1]==[none] ( call MyPrio ) else ( call MyPrio %1 )
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "ProcessID='%%myPID%%'" Get Priority /format:LIST`) do set myPrioAfter=%%b
start "" /b ping -t localhost > nul
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "name='ping.exe' AND ParentProcessID='%%myPID%%'" Get Priority /format:LIST`) do set pingPrio=%%b
for /f "usebackq tokens=2 delims==" %%b in (`wmic Process WHERE "name='ping.exe' AND ParentProcessID='%%myPID%%'" Get ProcessID /format:LIST`) do set pingPID=%%b
echo myPrioBefore==%myPrioBefore% / CALL MyPrio %1 / myPrioAfter==%myPrioAfter% / pingPrio==%pingPrio%
taskkill /f /pid %pingPID% > nul
exit /b

Это вывод партии тестеров:

myPrioBefore==4 / CALL MyPrio 64 / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio 16384 / myPrioAfter==6 / pingPrio==6
myPrioBefore==6 / CALL MyPrio 32 / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio 32768 / myPrioAfter==10 / pingPrio==8
myPrioBefore==10 / CALL MyPrio 128 / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio 256 / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio idle / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio "below normal" / myPrioAfter==6 / pingPrio==6
myPrioBefore==6 / CALL MyPrio none / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio normal / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio "idle" / myPrioAfter==4 / pingPrio==4
myPrioBefore==4 / CALL MyPrio "normal" / myPrioAfter==8 / pingPrio==8
myPrioBefore==8 / CALL MyPrio "above normal" / myPrioAfter==10 / pingPrio==8
myPrioBefore==10 / CALL MyPrio realtime / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio "high priority" / myPrioAfter==13 / pingPrio==8
myPrioBefore==13 / CALL MyPrio "realtime" / myPrioAfter==13 / pingPrio==8

Как вы можете видеть, myPrioAfter не соответствует запрошенному в вызове, и иногда приоритет ping не равен родительскому cmd поэтому значения должны быть больше (посмотрите на пятую строку: текущий приоритет равен 10, вы запрашиваете 128, новый приоритет - 13, а дочерний процесс - 8, извините?). Кроме того, в realtime кажется, не имеют эффекта (права администратора требуются, я предполагаю)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .