Paralelizar um loop for com um número muito grande de iterações

3

Eu quero paralelizar um loop for, em que o número de iterações no loop pode ser muito grande, como 10 ^ 6. Então, será melhor se eu puder criar threads em vez de processar. Como fazer isso? O código é o seguinte

N=$1

for (( i=0; i < $N; i++ )); do

    ./random >> output /* in each iteration one random number is appended to
                          a file "output" */                                

done
    
por RIchard Williams 03.12.2011 / 14:34

4 respostas

11

  1. Você não pode gerar threads de um shell.
  2. Você não deseja gravar no mesmo arquivo de vários processos.
  3. Se todo o seu programa random fizer é gerar um único número,
    • deve ser rápido o suficiente para que o seu loop seja ligado.
    • se você puder, você deve editá-lo para discutir e imprimir muitos números.
    • se a execução real é o gargalo, você deve repensar como gerar os números. Talvez postar o código para Revisão de código .

Se você realmente realmente ainda quiser fazer isso, faça isso em partes:

for i in {0..9}; do
    for ((j = 1; j < $N/10; j++)); do
        ./random
    done > tmp$i &
    pid[$i]=$?
done
for i in {0..9}; do
    wait ${pid[$i]}
done
cat tmp{0..9} >> outfile
    
por 03.12.2011 / 16:39
4

Não conheço nenhum shell que permita criar manualmente novos threads, normalmente você só pode utilizar os threads existentes no shell atual (ou criar subshells, que são de fato novos processos). Use python ou outro idioma.

Mesmo que você pudesse, eu realmente não recomendaria usar um script de shell para algo dessa escala. A perda de desempenho comparada a uma linguagem compilada ao executar iterações de 10 ^ 6 pode ser substancial.

    
por 03.12.2011 / 16:12
2

O problema, como sempre, é a contenção de recursos. Você precisa limitar o número de processos / threads que estão sendo executados ao mesmo tempo.

Além disso, ter encadeamentos simultâneos depende muito do tipo de processamento que será executado. É muito melhor se houver uma boa combinação de programação: memória, cpu, i / o, etc. Se todos os subprocessos estiverem fazendo todas as cpu, ter 10-20 rodando de uma só vez não acelera nada. Você poderia tentar extrair o processamento para outras máquinas; por exemplo. usando o ssh para iniciar chamadas em outras máquinas e obter os resultados de volta.

Um primeiro passo rápido e sujo pode ser algo como:

N=$1 # max number to iterate on
shift # rest of command line is the command to run: e.g. "./random"
maxcount=10 # maximum in the pool
curcount=0  # how many currently in the pool
reaper () {
    wait
    curcount='expr $curcount - 1'
}
spawnnext () {
    n=$1
    shift
    while [ $curcount -ge $maxcount ]; do
        sleep 1 # wait for a free slot in the pool
    done
    echo $n
    "$@" &
    curcount='expr $curcount + 1'
}

trap 'reaper' CHLD

for (( i=0; i < $N; i++)); do
    spawnnext $i "$@"
done

Nota; Eu não testei isso; apenas escrevi na hora.

Mas eu faria isso em uma linguagem de alto nível e melhor desempenho, como Python: link

    
por 03.12.2011 / 17:03
1

Se sua tarefa é simplesmente gerar números aleatórios:

perl -e 'for($t=0;$t<1000000;$t++) { print int(rand()*1000),"\n" }'

Se sua tarefa é realmente algo mais, você pode usar o GNU Parallel:

parallel ./random :::: <(seq 1000000) > output

Você pode instalar o GNU Parallel simplesmente por:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

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

    
por 05.12.2011 / 02:38