Comment exécuter des processus parallèles et combiner les sorties lorsque les deux sont terminés

17

J'ai un script shell bash dans lequel je canalise des données via environ 5 ou 6 programmes différents, puis les résultats finaux dans un fichier délimité par des tabulations.

Je refais ensuite la même chose pour un ensemble de données similaire distinct et je le renvoie dans un deuxième fichier.

Ensuite, les deux fichiers sont entrés dans un autre programme pour une analyse comparative. par exemple pour simplifier

Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv
AnalysisProg -i Data1res.csv Data2res.csv

Ma question est: comment puis-je faire fonctionner step1 et step2 en même temps (par exemple en utilisant &) mais lancer uniquement step3 (AnalysisProg) lorsque les deux sont terminés?

THX

ps AnalysisProg ne fonctionnera pas sur un flux ou fifo.

Stephen Henderson
la source
BTW, pouvez-vous utiliser des scripts Perl? Cela peut beaucoup simplifier la situation pour vous et vous pouvez mettre en œuvre ce post-traitement très efficacement et le faire fonctionner en parallèle sans effort.
Bichoy
Perl..pas tellement, non :(
Stephen Henderson
1
Ici, je montre comment diviser l'entrée entre des canaux avec teeet la traiter avec deux grepprocessus simultanés : unix.stackexchange.com/questions/120333/…
mikeserv
Et ici, je montre comment utiliser des constructions de shell simples pour créer un arrière-plan complet d'un processus de la même manière nohup, mais en conservant un moyen de communiquer avec le processus: unix.stackexchange.com/questions/121253/…
mikeserv

Réponses:

27

Utilisez wait. Par exemple:

Data1 ... > Data1Res.csv &
Data2 ... > Data2Res.csv &
wait
AnalysisProg

volonté:

  • exécuter les canaux Data1 et Data2 en tant que travaux d'arrière-plan
  • attendez qu'ils finissent tous les deux
  • exécutez AnalysisProg.

Voir, par exemple, cette question .

cxw
la source
Thx, ça a l'air bien. J'essaierai ceci si ce qui précède ne fonctionne pas.
Stephen Henderson
Thx encore, j'était un peu au courant d'attente , mais avoir googlé un peu a confondu la façon dont il a travaillé avec différents PID etc .. Je me sens stupide maintenant je vois qu'il est juste « attendre »
Stephen Henderson
12

La réponse de cxw est sans aucun doute la solution préférable, si vous n'avez que 2 fichiers. Si les 2 fichiers ne sont que des exemples et que vous avez en réalité 10000 fichiers, la solution '&' ne fonctionnera pas, car cela surchargerait votre serveur. Pour cela, vous avez besoin d'un outil comme GNU Parallel:

ls Data* | parallel 'cat {} | this | that |theother | grep |sed | awk |whatever > {}res.csv
AnalysisProg -i *res.csv

Pour en savoir plus sur GNU Parallel:

Ole Tange
la source
Salut thx. À l'heure actuelle, j'ai deux fichiers, mais j'ai 24 processeurs, donc je me sentais tenté d'essayer et d'exécuter plusieurs paires à la fois - bien que n'étant pas un informaticien, je ne sais pas si le goulot d'étranglement de la lecture du disque en vaudrait la peine. peut-être que je vais le sucer et voir;)
Stephen Henderson
@StephenHenderson selon la taille, les fichiers peuvent toujours être dans le cache. Si la vitesse est critique, vous pouvez simplement utiliser tmpfs (et les fichiers sont <<< puis votre RAM).
Maciej Piechotka
1
@StephenHenderson Le nombre de travaux parallèles peut être ajusté avec -j, donc essayez -j4 et si le serveur ne surcharge pas, essayez -j6 etc. Mais soyez prêt à appuyer sur CTRL-C: GNU Parallel est un excellent outil pour surcharger rapidement les serveurs . Jetez également un œil à --load.
Ole Tange
1

Une façon de procéder pourrait ressembler à ceci:

AnalysisProg <<PREPROCESS /dev/stdin
$( 
{   process1=$( pipe | line | 1 >&2 & echo $! )
    process2=$( pipe | line | 2 >&2 & echo $! )
    while ps -p $process1 $process2 >/dev/null; do
        sleep 1
    done
} 2>&1
)
#END
PREPROCESS

De cette façon, vous mettez en arrière plan les deux pipelines mais attendez toujours qu'ils finissent de s'exécuter avant de combiner leur sortie dans stdin qui est évalué dans un document ici et remis à AnalysisProg. Si vous pouvez l'utiliser, waitc'est encore mieux que la while psboucle, mais, en fonction du shell, vous waitpouvez vous opposer si vous lui demandez d'attendre un processus qui n'est pas un enfant du shell actuel.

Notez également que la méthode ci-dessus collationnera la sortie - donc les deux processus seront écrits en même temps. Si vous vouliez plutôt les séparer ou les ajouter les uns aux autres, vous pourriez peut-être faire:

AnalysisProg 3<<PREPROCESS /dev/fd/3 /dev/stderr
$(
process1=$(... >&2 ...) 2>/dev/fd/3
...
} 3>/dev/fd/3 2>/dev/stderr
)

J'ai déjà démontré ces concepts auparavant. Les meilleures démos sont probablement ici et ici .

mikeserv
la source
0

Essayez d'utiliser ceci.

rm -f Data1Res.csv
rm -f Data2Res.csv
Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv &
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv &
while true
do
  ps aux | grep -v grep | grep -i -E 'Data1Res.csv|Data2Res.csv' &> /dev/null
  if [ $? -ne 0 ]
  then
    AnalysisProg -i Data1res.csv Data2res.csv
    exit 0
  fi
done
Renan Vicente
la source
Eh bien, c'est lourd. N'est-ce pas comme réinventer waitla roue?
John WH Smith