Bash: vários para loops em segundo plano

8

Essa é a maneira correta de iniciar vários processamentos seqüenciais em segundo plano?

for i in {1..10}; do
    for j in {1..10}; do
        run_command $i $j;
    done &
done;

Todos jdevem ser processados ​​um após o outro por um determinado i, mas todos idevem ser processados ​​simultaneamente.

Rádio-controlado
fonte
O que você quer dizer com "caminho correto"?
Eran Ben-Natan
Principalmente isso funciona. Eu estava perdendo isso no stackoverflow.
Controlado por rádio
11
:-) Estou perguntando porque seu código funciona bem para mim. Se por "maneira correta" você quer dizer melhor prática, então eu iria colocar loop interno em uma função ou arquivo mesmo diferente, de modo a sua mais clara
Eran Ben-Natan

Respostas:

8

O loop externo que você tem é basicamente

for i in {1..10}; do
    some_compound_command &
done

Isso iniciaria dez instâncias simultâneas some_compound_commandem segundo plano. Eles serão iniciados o mais rápido possível, mas não totalmente "todos ao mesmo tempo" (ou seja, se some_compound_commanddemorar muito pouco, o primeiro poderá terminar antes do início do último).

O fato some_compound_commandde ser um loop não é importante. Isso significa que o código que você mostra está correto , pois as iterações do jloop interno serão executadas seqüencialmente, mas todas as instâncias do loop interno (uma por iteração do loop externo i) serão iniciadas simultaneamente.

A única coisa a ter em mente é que cada trabalho em segundo plano será executado em um subshell. Isso significa que as alterações feitas no ambiente (por exemplo, modificações nos valores das variáveis ​​do shell, alterações do diretório de trabalho atual com cd, etc.) em uma instância do loop interno não serão visíveis fora desse trabalho em segundo plano específico.

O que você pode querer adicionar é uma waitdeclaração após o loop, apenas para aguardar a conclusão de todos os trabalhos em segundo plano, pelo menos antes do término do script:

for i in {1..10}; do
    for j in {1..10}; do
        run_command "$i" "$j"
    done &
done

wait
Kusalananda
fonte
3

Se você possui o GNU Parallel, você faria:

parallel -j0 'for j in {1..10}; do run_command {} $j; done' ::: {1..10}

Um dos benefícios é que a saída da execução paralela run_commandsnão se mistura.

Ole Tange
fonte