Führen Sie einen Bash-Befehl aus, wenn ein Prozess abgeschlossen ist

Führen Sie einen Bash-Befehl aus, wenn ein Prozess abgeschlossen ist

Ich habe zwei Skripte, die GPU verwenden und ML-Modelle trainieren. Ich möchte sie starten, bevor ich schlafen gehe, damit sie nachts funktionieren und ich erwarte, am Morgen einige Ergebnisse zu sehen.

Da der GPU-Speicher jedoch begrenzt ist, möchte ich sie seriell statt parallel ausführen.

Ich kann es mit machen python train_v1.py && python train_v2.py; aber nehmen wir an, ich habe mit dem Training begonnen train_v1. Da das Training lange dauert, habe ich in der Zwischenzeit mit der Implementierung des zweiten Skripts begonnen und es beendet, train_v2.pyund ich möchte es automatisch ausführen, wenn python train_v1.pyes fertig ist.

Wie kann ich das erreichen? Danke.

Antwort1

Hier ist ein Ansatz, der keine Schleife erfordert und nicht überprüft, ob der andere Prozess noch aktiv ist, und auch keinen Aufruf train_v1.pyauf eine andere Art und Weise erfordert, als Sie es normalerweise tun würden:

$ python train_v1.py
^Z
[1]+  Stopped                 python train_v1.py
$ % && python train_v2.py

Das ist, wenn ich + ^Zdrücke , während der Prozess läuft, um ihn in den Ruhezustand zu versetzen, indem ich ihm ein Signal sende. Dann sage ich der Shell, dass sie ihn mit aufwecken soll , wobei ich es als Befehl verwende, dem ich am Ende das hinzufügen kann . Dadurch verhält es sich genauso, als ob Sie es von Anfang an getan hätten.CtrlZtrain_v1.pySIGTSTP%&& python train_v2.pypython train_v1.py && python train_v2.py

Anstelle von %können Sie auch verwenden fg. Das ist dasselbe. Wenn Sie mehr über diese Arten von Funktionen der Shell erfahren möchten, können Sie darüber inder Abschnitt "JOB CONTROL" der Manpage von bash.

EDIT: Wie kann ich weiterhin zur Warteschlange hinzufügen?

Wie jamesdlin in einem Kommentar anmerkt, train_v3.pywerden Sie feststellen, dass dies nicht möglich ist, wenn Sie versuchen, das Muster fortzusetzen, um beispielsweise vor dem Start von v2 Folgendes hinzuzufügen:

$ % && python train_v2.py
^Z
[1]+  Stopped                 python train_v1.py

Wird nur train_v1.pygestoppt, weil train_v2.pyes nicht gestartet wurde, und Sie können etwas nicht stoppen/anhalten/in den Ruhezustand versetzen, das noch nicht einmal gestartet wurde.

$ % && python train_v3.py

würde das gleiche Ergebnis bringen wie

python train_v1.py && python train_v3.py

weil %dies dem letzten angehaltenen Prozess entspricht. Anstatt zu versuchen, v3auf diese Weise hinzuzufügen, sollte man stattdessen die Geschichte verwenden:

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py

Man kann die Verlaufserweiterung wie oben durchführen oder den letzten Befehl mit einer Tastenkombination (z. B. „up“) abrufen und am Ende „v3“ hinzufügen.

$ % && python train_v2.py && python train_v3.py

Dies kann wiederholt werden, um der Pipeline mehr hinzuzufügen.

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
^Z
[1]+  Stopped                 python train_v1.py
$ !! && python train_v4.py
% && python train_v2.py && python train_v3.py && python train_v4.py

Antwort2

Wenn Sie bereits gestartet haben python train_v1.py, können Sie möglicherweise pgrepdiesen Prozess abfragen, bis er verschwindet, und dann Ihr zweites Python-Skript ausführen:

while pgrep -u "$USER" -fx 'python train_v1.py' >/dev/null
do
    # sleep for a minute
    sleep 60
done
python train_v2.py

Durch die Verwendung von -fund -xvergleichen Sie die genaue Befehlszeile, die zum Starten des ersten Python-Skripts verwendet wurde. Auf einigen Systemen pgrepimplementiert eine -qOption, die es leise macht (genau wie grep -q), was bedeutet, dass die Umleitung zu /dev/nullnicht erforderlich wäre.

Die -uOption beschränkt die Übereinstimmung auf Befehle, die Sie ausführen (und nicht auf die eines Freundes oder einer anderen Person auf demselben System).

Wenn Sie das erste Skript noch nicht gestartet haben:

Wie in den Kommentaren erwähnt, können Sie das zweite Skript direkt nach dem ersten Skript starten. Die Tatsache, dass das zweite Skript nicht existiert oder noch nicht ganz ausführungsbereit ist, spielt keine Rolle (solange es ausführungsbereit ist, wenn das erste Skript beendet ist):

python train_v1.py; python train_v2.py

Auf diese Weise wird das zweite Skript unabhängig vom Beendigungsstatus des ersten Skripts gestartet. Die Verwendung &&von anstelle von ;, wie Sie in der Frage zeigen, funktioniert ebenfalls, erfordert jedoch, dass das erste Skript erfolgreich beendet wird, damit das zweite Skript gestartet werden kann.

Antwort3

Sie können das erste Skript starten mit

python train_v1.py; touch finished

Dann machen Sie einfach eine Schleife, die regelmäßig prüft, ob Folgendes finishedexistiert:

while [ ! -f finished ] ; do     
    sleep 5
done
python train_v2.py
rm finished

Antwort4

Wenn Sie den Beendigungsstatus des ersten Skripts nicht kennen müssen, empfehle ich etwas wiewas Kusalananda schrieb.

Wenn Sie den Beendigungsstatus kennen müssen (was in diesem Fall wahrscheinlich nicht der Fall ist, aber jemand anders könnte vorbeikommen und nach einer Lösung suchen, die dies tut), ist es komplizierter. Ich habe einekleines Linux-DienstprogrammpwaitDamit können Sie auf die Beendigung eines Prozesses warten und seinen Beendigungsstatus erfahren.

verwandte Informationen