BASH: execução paralela

4

Eu tenho um script bash que recebe como entrada três matrizes com comprimento igual: METHODS , INFILES e OUTFILES .

Este script permitirá que METHODS[i] resolva o problema INFILES[i] e salve o resultado em OUTFILES[i] , para todos os índices i ( 0 <= i <= length-1 ).

Cada elemento em METHODS é uma string do formulário:

$HOME/program/solver -a <method>

em que solver é um programa que pode ser chamado da seguinte forma:

$HOME/program/solver -a <method> -m <input file> -o <output file> --timeout <timeout in seconds>

O script resolve todos os problemas em paralelo e define o limite de tempo de execução para cada instância em 1 hora (alguns métodos podem resolver alguns problemas muito rapidamente), como segue:

#!/bin/bash
source METHODS
source INFILES
source OUTFILES

start='date +%s'

## Solve in PARALLEL
for index in ${!OUTFILES[*]}; do 
    (alg=${METHODS[$index]}
    infile=${INFILES[$index]}
    outfile=${OUTFILES[$index]}

    ${!alg}  -m $infile -o $outfile --timeout 3600) &
done
wait


end='date +%s'

runtime=$((end-start))
echo "Total runtime = $runtime (s)"
echo "Total number of processes = ${#OUTFILES[@]}"

Acima, eu tenho length = 619 . Enviei esta festa para um cluster com 70 processadores disponíveis, o que deve levar no máximo 9 horas para concluir todas as tarefas. Este não é o caso na realidade, no entanto. Ao usar o comando top para investigar, descobri que apenas dois ou três processos estão em execução (estado = R ) enquanto todos os outros estão em repouso (estado = D ).

O que estou fazendo de errado, por favor?

Além disso, aprendi que o GNU paralelo seria muito melhor para executar trabalhos paralelos. Como posso usá-lo para a tarefa acima?

Muito obrigado pela sua ajuda!

Atualização: Minha primeira tentativa com o GNU paralelo:

A idéia é escrever todos os comandos em um arquivo e usar o GNU paralelo para executá-los:

#!/bin/bash
source METHODS
source INFILES
source OUTFILES

start='date +%s'    

## Write to file
firstline=true
for index in ${!OUTFILES[*]}; do 
    (alg=${METHODS[$index]}
    infile=${INFILES[$index]}
    outfile=${OUTFILES[$index]}
    if [ "$firstline" = true ] ; then
        echo "${!alg}  -m $infile -o $outfile --timeout 3600" > commands.txt
        firstline=false
    else
        echo "${!alg}  -m $infile -o $outfile --timeout 3600" >> commands.txt
    fi
done

## Solve in PARALLEL
time parallel :::: commands.txt

end='date +%s'

runtime=$((end-start))
echo "Total runtime = $runtime (s)"
echo "Total number of processes = ${#OUTFILES[@]}"

O que você acha?

Atualização 2: Estou usando o GNU paralelo e tendo o mesmo problema. Aqui está a saída de top :

top - 02:05:25 up 178 days,  8:16,  2 users,  load average: 62.59, 59.90, 53.29
Tasks: 596 total,   7 running, 589 sleeping,   0 stopped,   0 zombie
Cpu(s): 12.9%us,  0.9%sy,  0.0%ni, 63.3%id, 22.9%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  264139632k total, 260564864k used,  3574768k free,     4564k buffers
Swap: 268420092k total, 80593460k used, 187826632k free,    53392k cached

  PID USER     PR  NI  VIRT  RES  SHR S %CPU %MEM   TIME+   COMMAND
28542 khue     20   0 7012m 5.6g 1816 R  100  2.2  12:50.22 opengm_min_sum
28553 khue     20   0 11.6g  11g 1668 R  100  4.4  17:37.37 opengm_min_sum
28544 khue     20   0 13.6g 8.6g 2004 R  100  3.4  12:41.67 opengm_min_sum
28549 khue     20   0 13.6g 8.7g 2000 R  100  3.5   2:54.36 opengm_min_sum
28551 khue     20   0 11.6g  11g 1668 R  100  4.4  19:48.36 opengm_min_sum
28528 khue     20   0 6934m 4.9g 1732 R   29  1.9   1:01.13 opengm_min_sum
28563 khue     20   0 7722m 6.7g 1680 D    2  2.7   0:56.74 opengm_min_sum
28566 khue     20   0 8764m 7.9g 1680 D    2  3.1   1:00.13 opengm_min_sum
28530 khue     20   0 5686m 4.8g 1732 D    1  1.9   0:56.23 opengm_min_sum
28534 khue     20   0 5776m 4.6g 1744 D    1  1.8   0:53.46 opengm_min_sum
28539 khue     20   0 6742m 5.0g 1732 D    1  2.0   0:58.95 opengm_min_sum
28548 khue     20   0 5776m 4.7g 1744 D    1  1.9   0:55.67 opengm_min_sum
28559 khue     20   0 8258m 7.1g 1680 D    1  2.8   0:57.90 opengm_min_sum
28564 khue     20   0 10.6g  10g 1680 D    1  4.0   1:08.75 opengm_min_sum
28529 khue     20   0 5686m 4.4g 1732 D    1  1.7   1:05.55 opengm_min_sum
28531 khue     20   0 4338m 3.6g 1724 D    1  1.4   0:57.72 opengm_min_sum
28533 khue     20   0 6064m 5.2g 1744 D    1  2.1   1:05.19 opengm_min_sum

( opengm_min_sum é o solver acima)

Eu acho que alguns processos consomem tanto recurso que os outros não têm mais nada e entram no estado D?

    
por Khue 08.02.2017 / 00:51

2 respostas

2

Resumo dos comentários: A máquina é rápida, mas não tem memória suficiente para executar tudo em paralelo. Além disso, o problema precisa ler muitos dados e a largura de banda do disco não é suficiente, por isso, os processadores ficam ociosos a maior parte do tempo esperando pelos dados.

Reorganizar as tarefas ajuda.

Ainda não investigou a compactação dos dados para ver se pode melhorar a largura de banda efetiva de E / S de disco.

    
por 09.02.2017 / 01:21
3

A partir da versão 20160422, você pode fazer:

## Solve in PARALLEL
parallel {1} -m {2} -o {3} --timeout 3600 ::: "${METHODS[@]}" :::+ "${INFILES[@]}" :::+ "${OUTFILES[@]}"

Se você tem uma versão mais antiga:

## Solve in PARALLEL
parallel --xapply {1} -m {2} -o {3} --timeout 3600 ::: "${METHODS[@]}" ::: "${INFILES[@]}" ::: "${OUTFILES[@]}"

Passe uma hora percorrendo man parallel_tutorial . Sua linha de comando vai te amar por isso.

    
por 08.02.2017 / 01:06