Como executar processos paralelos e combinar saídas quando ambos terminarem

17

Eu tenho um script de shell bash no qual canalizo alguns dados por cerca de 5 ou 6 programas diferentes e, em seguida, os resultados finais em um arquivo delimitado por tabulação.

Em seguida, faço o mesmo novamente para um conjunto de dados semelhante separado e saio para um segundo arquivo.

Em seguida, os dois arquivos são inseridos em outro programa para análise comparativa. por exemplo, para simplificar

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

Minha pergunta é: como posso executar as etapas 1 e 2 ao mesmo tempo (por exemplo, usando &), mas apenas inicio a etapa3 (AnalysisProg) quando ambas estiverem concluídas?

valeu

ps O AnalysisProg não funcionará em um fluxo ou em um fifo.

Stephen Henderson
fonte
BTW, você pode usar scripts Perl? Isso pode simplificar muito o assunto para você e você pode implementar esse pós-processamento com muita eficiência e executá-lo em paralelo sem esforço.
Bichoy 28/03
Perl..not tanto, não :(
Stephen Henderson
1
Aqui eu demonstrar como dividir de entrada através de tubos com teee processá-lo com dois concorrentes grepprocessos: unix.stackexchange.com/questions/120333/...
mikeserv
E aqui eu demonstrar como usar construções de shell simples para totalmente fundo um processo no caminho nohupforça, mas ainda manter um meio de comunicação com o processo: unix.stackexchange.com/questions/121253/...
mikeserv

Respostas:

27

Use wait. Por exemplo:

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

vai:

  • executar os pipes Data1 e Data2 como trabalhos em segundo plano
  • espere que ambos terminem
  • execute o AnalysisProg.

Veja, por exemplo, esta pergunta .

cxw
fonte
Thx, isso parece bom. Vou tentar isso se o acima não funcionar.
Stephen Henderson
Thx novamente, eu era uma espécie de consciência de espera mas tendo pesquisei um pouco estava confuso de como ele trabalhou com diferentes PID etc .. Eu me sinto idiota agora vejo que é apenas "esperar"
Stephen Henderson
12

A resposta da cxw é sem dúvida a solução preferível, se você tiver apenas 2 arquivos. Se os 2 arquivos são apenas exemplos e, na realidade, você possui 10000 arquivos, a solução '&' não funcionará, pois isso sobrecarregará o servidor. Para isso, você precisa de uma ferramenta como o GNU Parallel:

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

Para saber mais sobre o GNU Parallel:

Ole Tange
fonte
Oi thx. No momento, tenho dois arquivos, mas tenho 24 processadores, por isso me senti tentado a tentar executar muitos pares de uma só vez - embora, como não seja uma pessoa da ciência da computação, não esteja claro se o gargalo na leitura do disco valeria a pena. talvez eu vou chupar-lo e ver;)
Stephen Henderson
@StephenHenderson, dependendo do tamanho, os arquivos ainda podem estar no cache. Se a velocidade for crítica, você pode simplesmente usar tmpfs (e os arquivos são <<<, então sua RAM).
Maciej Piechotka 28/03
1
@StephenHenderson O número de tarefas paralelas pode ser ajustado com -j, então tente -j4 e se o servidor não sobrecarregar, tente -j6 etc. Mas esteja pronto para pressionar CTRL-C: GNU Parallel é uma excelente ferramenta para sobrecarregar servidores rapidamente . Também dê uma olhada em --load.
precisa
1

Uma maneira de fazer isso pode ser algo como:

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

Dessa maneira, você coloca em segundo plano os dois pipelines, mas ainda espera que eles concluam a execução antes de combinar sua saída no stdin, que é avaliada em um documento aqui e entregue ao AnalysisProg. Se você pode usar waitisso, é ainda melhor que o while psloop, mas, dependendo do shell, waitpode se opor se você o instruir a aguardar um processo que não é filho do shell atual.

Observe também que o método acima agrupará a saída - portanto, os dois processos serão gravados de uma só vez. Se você os quisesse separados ou anexou um ao outro, possivelmente poderia:

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

Eu já demonstrei esses conceitos antes. Provavelmente as melhores demos estão aqui e aqui .

mikeserv
fonte
0

Tente usar isso.

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
fonte
Bem, isso é pesado. Não é como reinventar waita roda?
John WH Smith