Multithreading / Forking in einem Bash-Skript

9

Ich habe ein Bash-Skript geschrieben, das das folgende Format hat:

#!/bin/bash
start=$(date +%s)
inFile="input.txt"
outFile="output.csv"

rm -f $inFile $outFile

while read line
do

    -- Block of Commands

done < "$inFile"

end=$(date +%s)

runtime=$((end-start))

echo "Program has finished execution in $runtime seconds."

Die whileSchleife liest aus $inFile, führt einige Aktivitäten in der Zeile aus und gibt das Ergebnis aus $outFile.

Da das $inFileSkript mehr als 3500 Zeilen lang ist, würde die vollständige Ausführung des Skripts 6-7 Stunden dauern. Um diese Zeit zu minimieren, plane ich, in diesem Skript Multithreading oder Forking zu verwenden. Wenn ich 8 untergeordnete Prozesse erstelle, werden 8 Zeilen von $inFilegleichzeitig verarbeitet.

Wie kann das gemacht werden?

Mandar Shinde
quelle
Seien Sie vorsichtig: Verschiedene Skripte müssen in verschiedene Outfiles schreiben . Auch Ihr geschriebenes Skript löscht die Eingabedatei als erste Aktion!
pjc50

Antworten:

10

GNUparallel ist genau dafür gemacht. Sie können Ihr Skript mehrmals gleichzeitig ausführen, wobei für jedes einzelne unterschiedliche Daten aus Ihrer Eingabe eingespeist werden:

cat input.txt | parallel --pipe your-script.sh

Standardmäßig werden Prozesse entsprechend der Anzahl der Prozessoren auf Ihrem System erzeugt, aber Sie können dies mit anpassen -j N.

Ein besonders netter Trick ist die Shebang-Wrapping-Funktion. Wenn Sie die erste Zeile Ihres Bash-Skripts in Folgendes ändern:

#!/usr/bin/parallel --shebang-wrap --pipe /bin/bash

und füttere es mit Daten auf Standardeingabe, dann geschieht alles automatisch. Dies ist weniger nützlich, wenn Sie Bereinigungscode haben, der am Ende ausgeführt werden muss, was Sie möglicherweise tun.

Es gibt ein paar Dinge zu beachten. Eine davon ist, dass Ihre Eingabe in aufeinanderfolgende Blöcke zerlegt und diese einzeln verwendet werden - es werden keine Zeilen verschachtelt. Das andere ist, dass diese Chunks nach Größe aufgeteilt sind, unabhängig davon, wie viele Datensätze es gibt. Sie können --block Neine andere Blockgröße in Bytes festlegen. In Ihrem Fall sollte nicht mehr als ein Achtel der Dateigröße ungefähr richtig sein. Ihre Datei scheint klein genug zu sein, um ansonsten alle in einem einzigen Block zu landen, was den Zweck zunichte machen würde.

Es gibt viele Optionen für bestimmte unterschiedliche Anwendungsfälle, aber das Tutorial behandelt die Dinge ziemlich gut. Zu den Optionen, an denen Sie möglicherweise auch interessiert sind, gehören --round-robinund --group.

Michael Homer
quelle
1
Hast du diese Shebang-Linie getestet? Shebangs mit mehreren Argumenten sind nicht portierbar. Unter Linux #!a b cführt dies zu ["b c"], während dies auf einigen anderen Systemen der Fall ist ["b", "c"].
Nyuszika7h
1
Wenn es auf diese Weise verwendet wird, werden seine eigenen Argumente analysiert (andernfalls wäre die Option nicht sehr nützlich).
Michael Homer
@ MichaelHomer Ich muss zum GNU parallelScraping von HTML-Seiten verwenden. Könnten Sie bitte diesen Thread durchgehen unix.stackexchange.com/questions/277609/…
Swatesh Pakhare