Multithread-Windows FOR-Stapelbefehl

11

Wissen Sie, ob es eine einfache Möglichkeit gibt, den FOR- Befehl in einer Batchdatei auf mehreren Threads auszuführen ? Was bringt es, 4 Kerne zu haben, wenn ich meine Aufgaben nicht in 4 parallelen Threads ausführen kann?

Wenn ich beispielsweise PNGs mit PNGOUT optimiere, würde ich den Befehl verwenden

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

Dies ist jedoch eine sehr paralellierbare Aufgabe, bei der die Unteraufgaben überhaupt nicht voneinander abhängen.

Um dies in 4 'Warteschlangen' auszuführen, würde ich so etwas schreiben

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

Muss ich meine eigene For-Like-App schreiben, die dies kann, oder gibt es eine kostenlose Lösung?

Axarydax
quelle
Überprüfen Sie die folgende Antwort auf die Verwendung eines externen Tools: [ stackoverflow.com/a/12041213/365229[1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Antworten:

13

Ich habe vor einiger Zeit eine Batch-Datei geschrieben, die nur eine maximale Anzahl von Befehlen für den Stapelüberlauf ausführt: Parallele Ausführung von Shell-Prozessen :

@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

Es werden maximal vier neue Prozesse erzeugt, die parallel ausgeführt und minimiert werden. Die Wartezeit muss wahrscheinlich angepasst werden, je nachdem, wie viel jeder Prozess tut und wie lange er ausgeführt wird. Sie müssen wahrscheinlich auch den Prozessnamen anpassen, nach dem die Aufgabenliste sucht, wenn Sie etwas anderes tun.

Es gibt jedoch keine Möglichkeit, die Prozesse, die von diesem Stapel erzeugt werden, richtig zu zählen. Eine Möglichkeit wäre, zu Beginn des Stapels ( %RANDOM%) eine Zufallszahl zu erstellen und einen Hilfschargen zu erstellen , der die Verarbeitung ausführt (oder das Verarbeitungsprogramm erzeugt), dessen Fenstertitel jedoch auf einen Parameter festgelegt werden kann:

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

Dies wäre ein einfacher Stapel, der seinen Titel auf den ersten Parameter setzt und dann den zweiten Parameter mit dem dritten als Argument ausführt. Sie können dann in der Aufgabenliste filtern, indem Sie nur Prozesse mit dem angegebenen Fenstertitel ( tasklist /fi "windowtitle eq ...") auswählen . Dies sollte ziemlich zuverlässig funktionieren und zu viele Fehlalarme verhindern. Die Suche nach cmd.exewäre eine schlechte Idee, wenn noch einige Instanzen ausgeführt werden, da dies Ihren Pool an Arbeitsprozessen einschränkt.

Sie können verwenden %NUMBER_OF_PROCESSORS%, um eine sinnvolle Standardeinstellung für die Anzahl der zu erzeugenden Instanzen zu erstellen.

Sie können dies auch leicht anpassen psexec, um die Prozesse aus der Ferne zu erzeugen (dies wäre jedoch nicht sehr praktikabel, da Sie über Administratorrechte auf dem anderen Computer verfügen und das Kennwort im Stapel angeben müssen). Sie müssten dann jedoch Prozessnamen zum Filtern verwenden.

Joey
quelle
Das ist eine ernsthafte schwarze Magie! Ich wünschte, ich könnte öfter upvoten!
Axarydax
Nein, das ist ziemlich einfaches Zeug, sobald du den Dreh raus hast ;-)
Joey
Der Befehl 'wc' ist in meiner Win10-Befehlszeile nicht verfügbar. Was kann ich sonst noch verwenden?
PeterCo
1
@PeterCo : find /c /v "".
Joey
1

Batch-Dateien sind für extrem einfaches Scripting gedacht und unterstützen keinerlei Multithreading. Sie müssten Ihr eigenes Dienstprogramm schreiben, um das zu tun, was Sie erreichen möchten.

Alternativ bietet Windows PowerShell möglicherweise mehr Funktionen, um Ihrem Ziel näher zu kommen.

Wenn Sie einfach mehrere Vorgänge gleichzeitig ausführen möchten, können Sie mit dem Befehl start das Dienstprogramm PNGOUT in einem neuen Fenster starten. Die FOR-Schleife wird dann fortgesetzt, ohne auf den Abschluss jeder Operation zu warten.

Die modifizierte Zeile würde folgendermaßen aussehen:

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

Beachten Sie jedoch, dass dadurch PNGOUT für ALLE Dateien im Verzeichnis gleichzeitig effektiv gestartet wird, was höchstwahrscheinlich nicht wünschenswert ist.

Herohtar
quelle
Dies ist ein naiver Ansatz und wie Sie bereits erwähnt haben, wahrscheinlich nicht wünschenswert. Sie möchten nur so viele Prozesse starten, wie Sie über Kerne verfügen. Wenn Sie 4 Kerne und 1.000 Dateien haben, möchten Sie wirklich nur 4 Kerne gleichzeitig verarbeiten, bis alle 1.000 verarbeitet sind. Wenn Sie versuchen, alle 1.000 auf 4 Kernen gleichzeitig zu verarbeiten, verlangsamt sich Ihr Computer zu einem nutzlosen Crawl.
Adisak