Parallele Ausführung eines Programms für mehrere Dateien

7

Ich habe ein kleines Skript, das alle Dateien eines Ordners durchläuft und einen (normalerweise lang anhaltenden) Befehl ausführt. Im Grunde ist es

for file in ./folder/*;
do
    ./bin/myProgram $file > ./done/$file
done

(Bitte ignorieren Sie Syntaxfehler, es ist nur Pseudocode).

Ich wollte dieses Skript jetzt zweimal gleichzeitig ausführen. Offensichtlich ist die Ausführung nicht erforderlich, wenn ./done/$file vorhanden ist. Also habe ich das Skript in geändert

for file in ./folder/*;
do
    [ -f ./done/$file ] || ./bin/myProgram $file >./done/$file
done

Grundsätzlich stellt sich also die Frage: Ist es möglich, dass sich beide Skripte (oder im Allgemeinen mehr als ein Skript) tatsächlich am selben Punkt befinden und prüfen, ob die fehlgeschlagene doneDatei vorhanden ist und der Befehl zweimal ausgeführt wird?

es wäre einfach perfekt, aber ich bezweifle es sehr. Dies wäre zu einfach: D Wenn es vorkommen kann, dass sie dieselbe Datei verarbeiten, ist es dann möglich, die Skripte irgendwie zu "synchronisieren"?

stefan
quelle
Wenn Sie eine Version xargsmit der -Pverfügbaren Option haben, lesen Sie diese Frage .
jw013
2
GNU Make unterstützt auch die parallele Ausführung. Die done/$fileMarkierungen scheinen makemir ein wenig wie Ziele zu sein.
sr_
2
Der von Ihnen gepostete (Pseudo-) Code führt nicht zwei Instanzen Ihres Programms parallel aus. Wenn Sie entweder xargsoder GNU makeoder eine Version von haben parallel, müssen Sie dieses spezielle Rad nicht neu erfinden.
jw013
Es wird zwei Instanzen ausführen, wenn das obige Skript zweimal ausgeführt wird
stefan

Antworten:

4

Dies ist möglich und tritt in der Realität auf. Verwenden Sie eine Sperrdatei , um diese Situation zu vermeiden. Ein Beispiel von dieser Seite:

if mkdir /var/lock/mylock; then
    echo "Locking succeeded" >&2
else
    echo "Lock failed - exit" >&2
    exit 1
fi

# ... program code ...

rmdir /var/lock/mylock
Chris Down
quelle
1
"Nebenbei möchten Sie fast definitiv $ file zitieren." Es war nicht notwendig für meinen einfachen Job, aber offensichtlich dein Recht, dass es besser wäre, dies zu tun
stefan
@stefan - Ich habe es entfernt, als ich "Syntaxfehler ignorieren" sah ... :-)
Chris Down
: D Es ist vollkommen in Ordnung, wenn du mich an dieses Zeug erinnerst. Ich neige dazu, es zu vergessen, da ich noch nicht daran
gewöhnt
Ich liebe die Einfachheit der mkdir-Verriegelung. Danke für den Link! (Auch wenn ich es vorgezogen hätte, auf dieser Seite darüber zu lesen, möchten Sie vielleicht Ihre Antwort ein wenig erweitern?)
stefan
2

Die beiden Instanzen Ihres Skripts können auf diese Weise interagieren, wodurch der Befehl zweimal ausgeführt wird. Dies wird als Rennbedingung bezeichnet .

Eine Möglichkeit, diese Race-Bedingung zu vermeiden, besteht darin, dass jede Instanz ihre Eingabedatei abruft, indem sie in ein anderes Verzeichnis verschoben wird. Das Verschieben einer Datei (innerhalb desselben Dateisystems) ist atomar . Das Verschieben der Eingabedateien ist möglicherweise nicht wünschenswert, und dies wird bereits etwas kompliziert.

mkdir staging-$$ making-$$
for input in folder/*; do
  name=${x#folder/}
  staging=staging-$$/$name
  output=making-$$/$name
  destination=done/$name
  if mv -- "$input" "$staging" 2>/dev/null; then
    bin/myProgram "$staging" >"$output"
    mv -- "$output" "$destination"
    mv -- "$staging" "$input"
  fi
done

Eine einfache Möglichkeit, die Dateien mit einem weit verbreiteten Tool parallel zu verarbeiten, ist GNU make , wobei das -jFlag für die parallele Ausführung verwendet wird . Hier ist ein Makefile für diese Aufgabe (denken Sie daran, Tabulatoren zum Einrücken von Befehlen zu verwenden):

all: $(patsubst folder/%,done/%,$(wildcard folder/*))
done/%: folder/%
        ./bin/myProgram $< >$@.tmp
        mv $@.tmp $@

Ausführen make -j 3, um 3 Instanzen parallel auszuführen.

Siehe auch Vier Aufgaben parallel ... wie mache ich das?

Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank für diese Antwort. Wenn ich zwei Antworten akzeptieren könnte, würde ich!
Stefan
1

Ich habe das Gefühl, dass Sie wirklich versuchen, mehrere Jobs parallel auszuführen, und dass die Sperrdatei einfach ein Mittel zum Zweck ist.

Wenn Sie GNU Parallel http://www.gnu.org/software/parallel/ installiert haben, können Sie dies tun:

parallel ./bin/myProgram ::: ./folder/*

MyProgram wird auf jedem Kern parallel ausgeführt.

Sie können GNU Parallel einfach installieren, indem Sie:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

Sehen Sie sich die Intro-Videos für GNU Parallel an, um mehr zu erfahren: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Ole Tange
quelle
0

Das Problem beim Sperren besteht darin, dass Sie eine Methode benötigen, die eine unterbrechungsfreie Sperre erstellt (manchmal auch als atomar bezeichnet). Wie Chris in seiner Antwort geschrieben hat, mkdirhandelt es sich um eine solche unterbrechungsfreie Operation (das Erstellen einer Datei ist keine solche Operation).

Es gibt auch einen Befehl auf hoher Ebene - normalerweise im procmailPaket versteckt : lockfile. Dieser Befehl hat einige nette Funktionen und kann problemlos in Ihren eigenen Skripten verwendet werden, ohne dass Sie das Rad neu erfinden müssen (z. B. um Ihre eigene Funktion zu schreiben, die basierend auf der Verzeichniserstellung gesperrt wird).

Nils
quelle