Como posso executar vários trabalhos de shell paralelos e monitorar todos eles de uma vez?

Como posso executar vários trabalhos de shell paralelos e monitorar todos eles de uma vez?

Tenho um grande número de arquivos grandes (centenas de arquivos, centenas de MB cada) que preciso canalizar por meio de vários programas para filtrá-los e convertê-los. Estou aproveitando vários núcleos de CPU, então estou executando várias instâncias do mesmo pipe em cada arquivo (pode ter até cem núcleos e poderia usar ssh como parte do pipe, caso isso faça alguma diferença para o responder). Quero monitorar cada cano, e estou usando pvpara isso. Aqui está um exemplo mínimo do que tenho:

$ pv file-001.gz | gunzip | xz > file-001.xz
1.58GB 0:00:02 [ 713MB/s] [=================================>] 100%

Na realidade, eu também faço várias outras coisas no pipe, incluindo passar dados para outras máquinas através de ssh e canalizá-los através de filtros nessas máquinas, mas o pipe sempre terminaria com um redirecionamento para um novo arquivo no host principal. Além disso, nenhum estágio do tubo requer todo o conjunto de dados; eles podem operar linha por linha ou pedaço por pedaço.

Atualmente, preciso de uma janela de terminal separada para cada instância do pipe. O que eu gostaria de fazer é iniciar n instâncias paralelas do tubo em um único terminal/shell e obter a saída de cada instância pv em uma linha própria. Algo assim:

1.48GB 0:00:54 [ 704MB/s] [===============================>  ]  97% ETA 00:00:06
1.58GB 0:01:00 [ 713MB/s] [=================================>] 100%
0.75GB 0:00:31 [ 709MB/s] [================>                 ]  50% ETA 00:00:29

O valor para n seria o número de linhas que posso colocar em uma janela de terminal, digamos 3-50 ou mais. O formato exato do relatório de progresso não é importante, desde que inclua a velocidade, a percentagem concluída, o tempo decorrido e o tempo restante estimado. Também não é importante que eu use pv, não há problema em usar algum outro programa, desde que eu possa instalá-lo facilmente ou apenas um shell simples (bash, de preferência). O que é importante, porém, é que o método pode lidar com tubos quebrados ocasionais, caso uma parte do tubo se quebre por algum motivo. Eu também gostaria de iniciar novos trabalhos sempre que um trabalho for concluído (com sucesso ou não) e ainda houver arquivos não processados.

Algumas ideias em como fazer isso?

Observe que eu já tenteiParalelo GNU, mas seus recursos ssh parecem assumir que cada arquivo de entrada é primeiro transferido para o host remoto, depois processado e, em seguida, o resultado transferido de volta, o que quero evitar devido à quantidade de dados envolvidos e à quantidade limitada de espaço em cada processamento nó.

Responder1

Algumas ideias em como fazer isso?

Não.

pv tem opções -c e -N que devem permitir que você faça o que quiser

$ pv -cN source access.log | gzip | pv -cN gzip > access.log.gz
source:  760MB 0:00:15 [37.4MB/s] [=>     ] 19% ETA 0:01:02
  gzip: 34.5MB 0:00:15 [1.74MB/s] [  <=>  ]

mas não consigo ver como aplicar esse recurso a vários pipelines


No entanto, se você olhar a página de manual do pv, verá isto

          (tar cf - . \
           | pv -n -s $(du -sb . | awk '{print $1}') \
           | gzip -9 > out.tgz) 2>&1 \
          | dialog --gauge 'Progress' 7 70

Portanto, você pode estender isso para executar uma série de tarefas em paralelo, desde que seja aceitável visualizar o progresso em um cluster de pequenas janelas. Eu tentaria o Xdialog.

Atualmente, preciso de uma janela de terminal separada para cada instância do pipe

Meu ponto principal é que não é necessário que você abra interativamente muitas janelas de terminal; você pode fazer com que um script abra muitas caixas de diálogo.


Responder2

Você procurou --pipepelo GNU Parallel?

cat bigfiles* | pv | parallel --pipe -S server1,server2 'cat | process_pipe'

(gato incluído para ênfase)

O padrão é o tamanho do bloco de 1 MB, que pode ser ajustado com --block.

-- editar para correspondência 1-1 --

Com base no exposto, você pode obter correspondência 1-1 como esta:

parallel --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*

(gato incluído para ênfase)

Não é exatamente o ideal, pois o paralelo interno não saberá sobre seus irmãos e, portanto, poderá gerar mais no servidor1 do que no servidor2. Uma maneira de evitá-lo é -j1 no paralelo externo, mas isso não será ideal se o interno tiver blocos suficientes apenas para o primeiro servidor. Em outras palavras: para equilibrar perfeitamente sua carga de trabalho, talvez você precise mexer um pouco nisso - talvez até usar --load 100% ou similar.

--- editar: Lidar com falhas ---

Se process_piperetornar com um erro, deverá tentar novamente o comando mais 2 vezes:

parallel --retries 3 --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*

informação relacionada