Come eseguire processi paralleli e combinare gli output al termine di entrambi


17

Ho uno script di shell bash in cui installo alcuni dati attraverso circa 5 o 6 programmi diversi, quindi i risultati finali in un file delimitato da tabulazioni.

Quindi faccio di nuovo lo stesso per un set di dati simile separato e l'output in un secondo file.

Quindi entrambi i file vengono inseriti in un altro programma per l'analisi comparativa. ad es. per semplificare

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

La mia domanda è: come posso eseguire step1 e step2 contemporaneamente (es. Usando &) ma avviare step3 (AnalysisProg) solo quando entrambi sono completi?

grazie

ps AnalysisProg non funzionerà su uno stream o su fifo.



A proposito, va bene usare gli script Perl? Questo può semplificare molto la questione per te e puoi implementare questa post-elaborazione in modo molto efficiente e farla funzionare in parallelo senza sforzo.
Bichoy,

Perl..non tanto, no :(
Stephen Henderson,

1
Qui mostro come dividere l'input tra pipe con teeed elaborarlo con due grepprocessi simultanei : unix.stackexchange.com/questions/120333/…
mikeserv

E qui mostro come usare semplici costrutti di shell per creare un background completo di un processo, nohupma mantenendo comunque un mezzo per comunicare con il processo: unix.stackexchange.com/questions/121253/…
mikeserv

Risposte:


27

Usa wait. Per esempio:

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

volontà:

  • eseguire i tubi Data1 e Data2 come processi in background
  • aspetta che finiscano entrambi
  • eseguire AnalysisProg.

Vedi, ad esempio, questa domanda .


Grazie, sembra buono. Ci proverò se quanto sopra non funziona.
Stephen Henderson,

Thx ancora una volta, ero un po 'consapevole di attesa ma avendo googled un po' era confuso per come ha funzionato con diversi PID, ecc .. Mi sento stupido ora vedo si tratta solo di "aspettare"
Stephen Henderson

12

La risposta di cxw è senza dubbio la soluzione preferibile, se hai solo 2 file. Se i 2 file sono solo esempi e in realtà hai 10000 file, la soluzione '&' non funzionerà, in quanto sovraccaricherà il tuo server. Per questo è necessario uno strumento come GNU Parallel:

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

Per saperne di più su GNU Parallel:


Ciao grazie. In questo momento ho due file, ma ho 24 processori, quindi mi sentivo tentato di provare a eseguire più coppie contemporaneamente - anche se non essendo un esperto di informatica non sono chiaro se il collo di bottiglia della lettura del disco lo renderebbe utile. forse lo succherò e vedrò;)
Stephen Henderson il

@StephenHenderson a seconda della dimensione dei file può essere ancora nella cache. Se la velocità è fondamentale, puoi semplicemente usare tmpfs (ei file sono <<< quindi la tua RAM).
Maciej Piechotka,

1
@StephenHenderson Il numero di lavori paralleli può essere regolato con -j, quindi prova -j4 e se il server non si sovraccarica, prova -j6 ecc. Ma sii pronto a premere CTRL-C: GNU Parallel è uno strumento eccellente per sovraccaricare rapidamente i server . Dai anche un'occhiata a --load.
Ole Tange,

1

Un modo per farlo potrebbe essere simile a:

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

In questo modo si eseguono le background di entrambe le pipeline ma si attende ancora che finiscano l'esecuzione prima di combinare il loro output in stdin che viene valutato in un documento qui e consegnato ad AnalysisProg. Se puoi usarlo waitè anche meglio del while psciclo, ma, a seconda della shell, waitpuò obiettare se gli chiedi di aspettare un processo che non è figlio della shell corrente.

Si noti inoltre che il metodo precedente raccoglierà l'output, quindi entrambi i processi verranno scritti contemporaneamente. Se invece li volessi separati, o se li aggiungessi, potresti fare:

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

Ho dimostrato questi concetti prima. Probabilmente le migliori demo sono qui e qui .


0

Prova a usare questo.

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

Bene, quello è pesante. Non è come reinventare waitla ruota?
John WH Smith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.