Multi-Threading / Forking w skrypcie bash

9

Napisałem skrypt bash, który ma następujący format:

#!/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."

whilePętla będzie czytać od $inFilewykonać pewną aktywność na linii i zrzucić wynik w $outFile.

Ponieważ $inFilelinie mają ponad 3500 linii, wykonanie całego skryptu zajęłoby 6-7 godzin. Aby zminimalizować ten czas, planuję używać wielowątkowości lub rozwidlania w tym skrypcie. Jeśli utworzę 8 procesów potomnych, 8 wierszy z nich $inFilezostanie przetworzonych jednocześnie.

Jak można to zrobić?

Mandar Shinde
źródło
Uważaj: różne skrypty będą musiały pisać do różnych plików wyjściowych. Również twój skrypt w postaci napisanej usuwa plik wejściowy jako pierwszą akcję!
pjc50

Odpowiedzi:

10

GNUparallel jest stworzony właśnie do tego rodzaju rzeczy. Możesz uruchamiać skrypt wiele razy na raz, dla każdego przesyłając różne dane z danych wejściowych:

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

Domyślnie spawnuje procesy zgodnie z liczbą procesorów w twoim systemie, ale możesz to dostosować za pomocą -j N.

Szczególnie zgrabną sztuczką jest funkcja owijania shebang. Jeśli zmienisz pierwszą linię skryptu Bash na:

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

i podaj dane na standardowym wejściu, to wszystko stanie się automatycznie. Jest to mniej przydatne, gdy masz kod czyszczenia, który musi zostać uruchomiony na końcu, co możesz zrobić.

Należy zwrócić uwagę na kilka rzeczy. Jednym z nich jest to, że podzieli dane wejściowe na sekwencyjne fragmenty i wykorzysta je pojedynczo - nie przeplata linii. Drugi polega na tym, że te fragmenty są podzielone według wielkości, bez względu na liczbę rekordów. Możesz użyć, --block Naby ustawić inny rozmiar bloku w bajtach. W twoim przypadku nie więcej niż jedna ósma rozmiaru pliku powinna być odpowiednia. Twój plik wygląda na to, że może być wystarczająco mały, aby skończyć w jednym bloku w przeciwnym razie, co by zniweczyło cel.

Istnieje wiele opcji dla poszczególnych różnych przypadków użycia, ale samouczek omawia wszystko całkiem dobrze. Opcje, które mogą Cię również zainteresować, obejmują --round-robini --group.

Michael Homer
źródło
1
Czy przetestowałeś tę linię shebang? Szeregi z wieloma argumentami są nieprzenośne. W systemie Linux #!a b cspowoduje to ["b c"], podczas gdy w niektórych innych systemach spowoduje ["b", "c"].
nyuszika7h
1
Używa w ten sposób własnych argumentów (w przeciwnym razie opcja nie byłaby zbyt użyteczna).
Michael Homer
@MichaelHomer Muszę użyć GNU paralleldo skrobania stron HTML. Czy możesz przejść przez ten wątek unix.stackexchange.com/questions/277609/...
Swatesh Pakhare