Multi-Threading / Forking dans un script bash

9

J'ai écrit un script bash au format suivant:

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

La whileboucle va lire $inFile, effectuer une activité sur la ligne et vider le résultat $outFile.

Comme la $inFilelongueur de 3500+ lignes, le script prendrait 6-7 heures pour s'exécuter complètement. Afin de minimiser ce temps, je prévois d'utiliser le multi-threading ou le forking dans ce script. Si je crée 8 processus enfants, 8 lignes du $inFileseront traitées simultanément.

Comment cela peut-il être fait?

Mandar Shinde
la source
Attention: différents scripts devront écrire dans différents fichiers externes. De plus, votre script tel qu'il est écrit supprime le fichier d'entrée comme première action!
pjc50

Réponses:

10

GNUparallel est fait pour ce genre de chose. Vous pouvez exécuter votre script plusieurs fois à la fois, avec des données différentes de votre entrée intégrées pour chacune:

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

Par défaut, il générera des processus en fonction du nombre de processeurs sur votre système, mais vous pouvez le personnaliser avec -j N.

Une astuce particulièrement intéressante est la fonction d'emballage de shebang. Si vous changez la première ligne de votre script Bash en:

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

et lui fournir des données sur une entrée standard, tout se fera automatiquement. Cela est moins utile lorsque vous avez du code de nettoyage qui doit s'exécuter à la fin, ce que vous pouvez faire.

Il y a deux ou trois choses à noter. La première est qu'il découpera votre entrée en morceaux séquentiels et les utilisera un par un - il n'entrelace pas les lignes. L'autre est que ces morceaux sont divisés par taille, sans tenir compte du nombre d'enregistrements. Vous pouvez utiliser --block Npour définir une taille de bloc différente en octets. Dans votre cas, pas plus d'un huitième de la taille du fichier devrait être à peu près correct. Votre fichier semble être assez petit pour finir dans un seul bloc, ce qui irait à l'encontre de l'objectif.

Il existe de nombreuses options pour différents cas d'utilisation, mais le didacticiel couvre assez bien les choses. Les options qui pourraient également vous intéresser incluent --round-robinet --group.

Michael Homer
la source
1
Avez-vous testé cette ligne de shebang? Les shebangs avec plusieurs arguments ne sont pas transférables. Sous Linux, #!a b cil en résultera ["b c"], tandis que sur certains autres systèmes, il en résultera ["b", "c"].
nyuszika7h
1
Il ré-analyse ses propres arguments lorsqu'il est utilisé de cette manière (sinon l'option ne serait pas très utile).
Michael Homer
@MichaelHomer que je dois utiliser GNU parallelpour gratter des pages HTML. Pourriez-vous s'il vous plaît passer par ce fil unix.stackexchange.com/questions/277609/…
Swatesh Pakhare