Bash: espera por um número fixo de processo

5

Eu escrevi um script bash que executa um jar de Java para um número de n de vezes.

Na prática, eu defini a função e foo () , contendo a invocação do jar , e então eu rodei este script:

for RUN in $(seq 1 $RUNS) 
do 
    foo & 
done

Agora, eu gostaria de não executar runs vezes em paralelo o jar . Há uma espera para limitar o número de execuções paralelas (como um wait a cada 10 processos, por exemplo)?

    
por Giovanni Grano 25.01.2018 / 14:58

3 respostas

5

bash versão 4.4 introduziu uma nova linguagem útil chamada transformação de parâmetro que pode ajudá-lo neste caso. No snippet de código abaixo, observe o uso de ${num_jobs@P} . O @P é um tipo de transformação de parâmetro que faz com que a variável seja expandida como se fosse uma sequência de caracteres bash . Veja man bash para outras opções transformação de parâmetro .

#!/bin/bash
num_procs=$1
num_iters=$2
num_jobs="\j"  # The prompt escape for number of jobs currently running
for ((i=0; i<num_iters; i++)); do
  while (( ${num_jobs@P} >= num_procs )); do
    wait -n
  done
  foo &
done

Créditos para chepner no link .

Após o comentário de Kusalananda, se necessário, a fim de tornar este grupo de processos independente de quaisquer outros trabalhos em segundo plano que possam afetar a contagem, você pode envolvê-los com seu próprio shell. Para isso, são necessárias algumas mudanças.

#!/bin/bash
# start a wrapper shell for the group of jobs
cat<<EOS | bash &
num_procs="$1"
num_iters="$2"
for ((i=0; i<num_iters; i++)); do
  # escape what's not supposed to be expanded
  # at the time of here-doc redirection
  while (( \${num_jobs@P} >= num_procs )); do  
    wait -n
  done
  foo &
done
EOS
# now you can do other things
    
por 25.01.2018 / 15:30
3
for RUN in $(seq 1 $RUNS); do
    foo &

    if (( (RUN % 10) == 0 )); then
        wait
    fi
done

ou, com uma construção alternativa de loop (IMHO mais bonito):

for (( r = 1; r <= RUNS; ++i )); do
    foo &

    if (( (r % 10) == 0 )); then
        wait
    fi
done

Você também pode querer um wait após o loop se $RUNS não for um múltiplo de 10.

Em vez de ter RUNS como o número total de execuções a serem realizadas, também é possível imaginar n de lotes de 10 trabalhos:

for (( i = 0; i < n; ++i )); do
    printf 'starting batch %d...\n' "$i"
    for (( j = 0; j < 10; ++j )); do
        foo &
    done

    echo 'waiting...'
    wait
done

Solução alternativa usando xargs e não explícito wait :

seq 1 "$RUNS" | xargs -n 1 -P 10 foo

Isso, no entanto, daria ao processo foo um argumento de linha de comando (um dos inteiros produzidos por seq ), que pode não ser desejado. Isso elimina esse problema:

seq 1 "$RUNS" | xargs -n 1 -P 10 sh -c 'foo'
    
por 25.01.2018 / 15:23
1

O GNU Parallel é feito exatamente para isso:

seq 1 $RUNS | parallel -j 10 -N0 foo

O padrão é executar um trabalho por núcleo da CPU:

seq 1 $RUNS | parallel -N0 foo

O GNU Parallel é um paralelizador geral e facilita a execução de trabalhos em paralelo na mesma máquina ou em várias máquinas para as quais você tem acesso ssh.

Se você tem 32 tarefas diferentes que você quer rodar em 4 CPUs, uma forma direta de paralelizar é rodar 8 tarefas em cada processador:

O

GNUParallelgeraumnovoprocessoquandoumtermina-mantendoasCPUsativaseeconomizandotempo:

Instalação

Por razões de segurança, você deve instalar o GNU Parallel com seu gerenciador de pacotes, mas se o GNU Parallel não estiver empacotado para sua distribuição, você pode fazer uma instalação pessoal, que não requer acesso root. Isso pode ser feito em 10 segundos ao fazer isso:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Para outras opções de instalação, consulte o link

Saiba mais

Veja mais exemplos: link

Assista aos vídeos de introdução: link

Percorra o tutorial: link

Inscreva-se na lista de e-mail para obter suporte: link

    
por 28.03.2018 / 22:40