Bash-Skript parallelisieren

8

Ich brauche die Summe einer ganzen Zahl in mehreren Webseiten. getPages() analysiert die ganze Zahl und setzt sie auf $subTotal . getPages() wird in einer for-Schleife im Hintergrund aufgerufen, aber wie bekomme ich die Summe von $subTotal ? Ist das ein Subshelling-Problem?

Das habe ich bisher versucht.

%Vor%

Irgendein Rat geschätzt.

    
Eric Fortis 04.07.2011, 19:45
quelle

2 Antworten

4

Ja, das ist ein Subshelling-Problem. Alles, was in einer ... & -Liste (d. H. Ihre getPages $KEY $VALUE & ) ausgeführt wird, wird in einer Subshell ausgeführt, was bedeutet, dass Änderungen von Variablen dort die Eltern-Shell nicht beeinflussen.

Ich denke, man könnte etwas mit Coprozessionen (dh Kommunikation durch Streams) machen, oder vielleicht GNU parallel oder < a href="http://www.gnu.org/software/pexec/"> pexec .

Hier ist ein Beispiel mit pexec , das die Standardausgabe verwendet, um von den einzelnen Prozessen zu kommunizieren. Ich habe einen einfacheren Befehl verwendet, da die von Ihnen aufgelisteten Server von hier aus nicht erreichbar sind. Dies zählt die Zeilen auf einigen Webseiten und fasst sie zusammen.

%Vor%

Wir verwenden hier einige Tricks:

  • Wir leiten die Ausgabe der parallelen Prozesse zurück zum Hauptprozess und lesen sie dort in einer Schleife.
  • Um das Erstellen einer Subshell für die while-Schleife zu vermeiden, verwenden wir die bash-Funktion zur Prozesssubstitution ( <( ... ) ) zusammen mit der Eingabeumleitung ( < ) anstelle einer einfachen Pipe.
  • Wir arithmetieren in einem Befehl (( ... )) arithmetischer Ausdruck. Ich hätte stattdessen let verwenden können, aber dann müsste ich alles zitieren oder Leerzeichen vermeiden. (Ihre total=$(( total + subtotal )) hätte auch funktioniert.)
  • die Optionen zu pexec :
    • --normal-redirection bedeutet, dass alle Ausgabeströme aus den Teilprozessen zusammen in den Ausgabestream von pexec umgeleitet werden. (Ich bin mir nicht sicher, dass dies zu Verwirrung führen könnte, wenn zwei Prozesse gleichzeitig schreiben möchten.)
    • --environment hostname übergibt den abweichenden Parameter für jede Ausführung als Umgebungsvariable. Sonst wäre es ein einfaches Befehlszeilenargument.
    • --number ${#ARRAY[*]} (die in unserem Fall --number 4 erhält) stellt sicher, dass alle Prozesse parallel gestartet werden, anstatt nur so viele wie wir CPUs oder eine andere Heuristik haben. (Dies ist für Netzwerk-Roundtrip-gebundene Arbeit. Für CPU-gebundene oder bandbreitengebundene Sachen wäre eine kleinere Zahl besser.)
    • --shell-command stellt sicher, dass der Befehl von einer Shell ausgewertet wird, anstatt zu versuchen, ihn direkt auszuführen. Dies ist notwendig wegen der Pipeline dort.
    • --parameters "${ARRAY[@]}" listet die tatsächlichen Argumente auf - d. h. die Elemente des Arrays. Für jede von ihnen wird eine separate Version des Befehls gestartet.
    • Nach dem letzten -- kommt der Befehl - als einzelner ' -Quote-String, um eine vorzeitige Interpretation des $hostname dort durch die äußere Shell zu vermeiden. Der Befehl simple lädt die Datei herunter und leitet sie an wc -l , wobei die Zeilen gezählt werden.

Beispielausgabe:

%Vor%

Hier ist (ein Teil davon) die Ausgabe von ps -f , während diese ausgeführt wird:

%Vor%

Wir können sehen, dass wirklich alles parallel läuft, so viel wie möglich auf meinem Ein-Prozessor-System.

    
Paŭlo Ebermann 04.07.2011, 21:12
quelle
0

Eine kürzere Version mit GNU Parallel:

%Vor%

Wenn der host: port in einer Datei ist:

%Vor%

Erfahren Sie mehr: Ссылка

    
Ole Tange 03.02.2013 15:34
quelle

Tags und Links