Bash: Mehrere for-Schleifen im Hintergrund

8

Ist dies der richtige Weg, um mehrere aufeinanderfolgende Verarbeitungen im Hintergrund zu starten?

for i in {1..10}; do
    for j in {1..10}; do
        run_command $i $j;
    done &
done;

Alle jsollten für eine bestimmte Zeit nacheinander verarbeitet werden i, aber alle isollten gleichzeitig verarbeitet werden.

Funkgesteuert
quelle
Was meinst du mit "richtigem Weg"?
Eran Ben-Natan
Hauptsächlich, dass es funktioniert. Ich habe dies beim Stackoverflow vermisst.
Radio Controlled
1
:-) Ich frage, weil dein Code für mich gut funktioniert. Wenn Sie mit "richtigem Weg" Best Practice meinen, dann würde ich die innere Schleife in eine Funktion oder sogar eine andere Datei einfügen, damit es klarer wird
Eran Ben-Natan

Antworten:

8

Die äußere Schleife, die Sie haben, ist im Grunde

for i in {1..10}; do
    some_compound_command &
done

Dies würde zehn gleichzeitige Instanzen von some_compound_commandim Hintergrund starten . Sie werden so schnell wie möglich gestartet, aber nicht ganz "alle zur gleichen Zeit" (dh wenn es sehr wenig Zeit in Anspruch some_compound_commandnimmt , kann die erste gut enden, bevor die letzte beginnt).

Die Tatsache, dass es sich some_compound_commandzufällig um eine Schleife handelt, ist nicht wichtig. Dies bedeutet, dass der von Ihnen angezeigte Code insofern korrekt ist , als die Iterationen der inneren jSchleife nacheinander ausgeführt werden, aber alle Instanzen der inneren Schleife (eine pro Iteration der äußeren iSchleife) gleichzeitig gestartet werden.

Das einzige, was Sie beachten sollten, ist, dass jeder Hintergrundjob in einer Subshell ausgeführt wird. Dies bedeutet, dass Änderungen an der Umgebung (z. B. Änderungen an Werten von Shell-Variablen, Änderungen des aktuellen Arbeitsverzeichnisses mit cdusw.) in einer Instanz der inneren Schleife außerhalb dieses bestimmten Hintergrundjobs nicht sichtbar sind.

Was Sie möglicherweise hinzufügen möchten, ist eine waitAnweisung nach Ihrer Schleife, um zu warten, bis alle Hintergrundjobs tatsächlich beendet sind, zumindest bevor das Skript beendet wird:

for i in {1..10}; do
    for j in {1..10}; do
        run_command "$i" "$j"
    done &
done

wait
Kusalananda
quelle
3

Wenn Sie GNU Parallel haben, würden Sie Folgendes tun:

parallel -j0 'for j in {1..10}; do run_command {} $j; done' ::: {1..10}

Einer der Vorteile ist, dass die Ausgabe aus dem parallelen Betrieb run_commandsnicht gemischt wird.

Ole Tange
quelle