Wielowątkowe polecenie wsadowe systemu Windows FOR

11

czy wiesz, czy istnieje prosty sposób na uruchomienie polecenia FOR w pliku wsadowym w wielu wątkach? Jaki jest sens posiadania 4 rdzeni, jeśli nie mogę uruchomić moich zadań w 4 równoległych wątkach?

Na przykład, jeśli optymalizuję PNG za pomocą PNGOUT, poleceniem, którego użyłbym, jest

for %i in (*.png) do pngout "%i"

Ale jest to wysoce paraliżowalne zadanie, w którym pod-zadania w ogóle nie zależą od siebie.

Aby uruchomić to w 4 „kolejkach”, napisałbym coś takiego

for -thread 4 %i in (*.png) do pngout "%i"

Czy muszę napisać własną aplikację, która byłaby w stanie to zrobić, czy jest dostępne bezpłatne rozwiązanie?

Axarydax
źródło
sprawdź następującą odpowiedź na temat korzystania z zewnętrznego narzędzia: [ stackoverflow.com/a/12041213/365229][1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Odpowiedzi:

13

Napisałem plik wsadowy, który jakiś czas temu wykonuje tylko maksymalną liczbę poleceń na przepełnieniu stosu: Równoległe wykonywanie procesów powłoki :

@echo off
for /l %%i in (1,1,20) do call :loop %%i
goto :eof

:loop
call :checkinstances
if %INSTANCES% LSS 5 (
    rem just a dummy program that waits instead of doing useful stuff
    rem but suffices for now
    echo Starting processing instance for %1
    start /min wait.exe 5 sec
    goto :eof
)
rem wait a second, can be adjusted with -w (-n 2 because the first ping returns immediately;
rem otherwise just use an address that's unused and -n 1)
echo Waiting for instances to close ...
ping -n 2 ::1 >nul 2>&1
rem jump back to see whether we can spawn a new process now
goto loop
goto :eof

:checkinstances
rem this could probably be done better. But INSTANCES should contain the number of running instances afterwards.
for /f "usebackq" %%t in (`tasklist /fo csv /fi "imagename eq wait.exe"^|find /v /c ""`) do set INSTANCES=%%t
goto :eof

Odradza się maksymalnie cztery nowe procesy, które są wykonywane równolegle i zminimalizowane. Prawdopodobnie czas oczekiwania należy dostosować w zależności od tego, ile kosztuje każdy proces i jak długo trwa. Prawdopodobnie musisz także zmienić nazwę procesu, którego szuka lista zadań, jeśli robisz coś innego.

Jednak nie ma sposobu, aby poprawnie policzyć procesy, które są odradzane przez tę partię. Jednym ze sposobów byłoby utworzenie losowej liczby na początku partii ( %RANDOM%) i utworzenie partii pomocniczej, która wykonuje przetwarzanie (lub spawnuje program przetwarzający), ale która może ustawić tytuł okna na parametr:

@echo off
title %1
"%2" "%3"

Byłaby to prosta partia, która ustawia swój tytuł na pierwszy parametr, a następnie uruchamia drugi parametr z trzecim jako argumentem. Następnie można filtrować listę zadań, wybierając tylko procesy o określonym tytule okna ( tasklist /fi "windowtitle eq ..."). Powinno to działać dość niezawodnie i zapobiegać zbyt wielu fałszywym pozytywom. Wyszukiwanie cmd.exebyłoby złym pomysłem, jeśli nadal masz uruchomione niektóre instancje, ponieważ ogranicza to pulę procesów roboczych.

Możesz użyć, %NUMBER_OF_PROCESSORS%aby stworzyć rozsądną wartość domyślną liczby instancji do odrodzenia.

Możesz również łatwo to dostosować, aby używać psexecdo zdalnego odradzania procesów (ale nie byłoby to bardzo opłacalne, ponieważ musisz mieć uprawnienia administratora na innym komputerze, a także podać hasło w partii). Trzeba jednak użyć nazw procesów do filtrowania.

Joey
źródło
to jest poważna czarna magia partii! Chciałbym móc głosować więcej razy!
Axarydax,
Nie, to dość podstawowa rzecz, kiedy już się zorientujesz ;-)
Joey
Polecenie „wc” nie jest dostępne w moim wierszu poleceń Win10. Czego mogę użyć jeszcze?
PeterCo
1
@PeterCo: find /c /v "".
Joey
1

Pliki wsadowe są przeznaczone do bardzo podstawowych skryptów i nie obsługują żadnego rodzaju wielowątkowości. Będziesz musiał napisać własne narzędzie do robienia tego, co chcesz osiągnąć.

Alternatywnie, Windows PowerShell może zapewnić więcej możliwości, aby zbliżyć się do celu.

Jeśli chcesz po prostu uruchomić wiele operacji jednocześnie, możesz użyć polecenia start, aby uruchomić narzędzie PNGOUT w nowym oknie. Pętla FOR będzie kontynuowana bez oczekiwania na zakończenie każdej operacji.

Zmodyfikowana linia wyglądałaby następująco:

for %i in (*.png) do start pngout "%i"

Należy jednak pamiętać, że spowoduje to skuteczne uruchomienie PNGOUT dla WSZYSTKICH plików w katalogu w tym samym czasie, co najprawdopodobniej nie jest pożądane.

Herohtar
źródło
Jest to naiwne podejście i jak wspominasz, prawdopodobnie nie jest pożądane. Chcesz uruchomić tyle procesów, ile masz rdzeni. Jeśli masz 4 rdzenie i 1000 plików, naprawdę chcesz przetwarzać tylko 4 naraz, dopóki wszystkie 1000 nie zostaną przetworzone. Jeśli spróbujesz przetworzyć wszystkie 1000 jednocześnie na 4 rdzeniach, komputer zwolni do bezużytecznego indeksowania.
Adisak,