como executar vários scripts de shell em paralelo

3

Eu tenho alguns scripts de teste, cada um dos quais executa um aplicativo PHP de teste. Cada script é executado para sempre.

Portanto, cat.sh , dog.sh e foo.sh cada um executa um script PHP. Cada script de shell executa o aplicativo PHP em um loop, então ele é executado para sempre, dormindo após cada execução.

Estou tentando descobrir como executar os scripts em paralelo ao mesmo tempo. Veja a saída dos aplicativos PHP na janela stdout / term.

Eu pensei, fazer algo como o seguinte pode funcionar:

foo.sh > &2
dog.sh > &2
cat.sh > &2

Em um script de shell, isso seria suficiente, mas não está funcionando.

foo.sh, runs foo.php once, and it runs correctly
dog.sh, runs dog.php in a never ending loop. it runs as expected
cat.sh, runs cat.php in a never ending loop
 *** this never runs!!!

Parece que o script de shell nunca executa cat.sh . Se eu executar cat.sh sozinho em uma janela / termo separada, ele será executado conforme o esperado.

Alguém tem alguma ideia de como eu posso fazer esses scripts rodarem em paralelo?

    
por tom smith 27.03.2012 / 23:08

4 respostas

10

Sua configuração atual está executando seus comandos sequencialmente. O primeiro é executado, e completa , permitindo que o segundo seja iniciado. O segundo nunca acaba, então o terceiro nunca tem a chance de começar.

Tente isto:

foo.sh >foo.out 2>foo.err &
dog.sh >dog.out 2>dog.err &
cat.sh >cat.out 2>cat.err &

Isso dirá que cada comando deve ser executado em segundo plano e enviar suas informações de saída e erro para os arquivos. Quando um comando é executado em segundo plano, ele se desconecta da sessão atual e permite que o próximo comando seja executado. É importante colocar o e comercial ( & ) como o último caractere da linha. Caso contrário, pode não ser reconhecido corretamente.

Como alternativa, faça com que cada um dos seus scripts de shell execute o script .php associado que você está aparentemente chamando com a mesma semântica descrita acima. Nesse cenário, seu foo.sh pode conter:

#!/bin/bash
php foo.php >foo.out 2>foo.err &

Finalmente, se você precisar de uma verdadeira operação paralela, confira o Paralelo GNU .

Nota: Se você realmente quer que a saída vá para a tela / terminal, você pode deixar o redirecionamento de saída:

foo.sh &

Lembre-se, porém, que rodar múltiplos comandos ao mesmo tempo pode causar saída confusa (você pode agora saber qual saída ou erros vieram de qual comando), e se você sair, a saída não tem para onde ir.

    
por 28.03.2012 / 01:37
6

Isso pode ser feito com o comando paralelo.

Belos exemplos: paralelo

[me@neo]<bash><~> 19
05:51 Tue Mar 05 > man -f parallel
parallel (1) - run programs in parallel

-

parallel -j 3 -- "sh foo.sh" "sh dog.sh" "sh cat.sh"

Isso iniciará 3 scripts em paralelo, ao mesmo tempo.

parallel sh -c "echo hi; sleep 2; echo bye" -- 1 2 3

Isso iniciará por padrão como muitos processos do mesmo comando, dependendo da contagem de cpu.

parallel -j 3 sh -c "echo hi; sleep 2; echo bye" -- 1 2 3

Isso forçará a execução de 3 processos ao mesmo tempo, mesmo se você tiver apenas 2 cpu's.

Exemplo:

[me@neo]<bash><~> 31 
06:09 Tue Mar 05 > parallel -j 10 sh -c "echo Hello World; sleep 3; echo Good morning" -- $(seq 1 10)

Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Good morning
Good morning
Good morning
Good morning
Good morning
Good morning
Good morning
Good morning
Good morning
Good morning
    
por 05.03.2013 / 04:59
2

Chris tem uma boa ideia geral para a maioria dos scripts: termine cada comando com & e eles entrarão em segundo plano. Dito isto, aqui está o meu algo que guardo para algumas tarefas mais avançadas. Deixe-me apresentar o meu prático script de ferramentas, parallel-exec.pl

    #!/usr/bin/perl
    use threads;
    use Thread::Queue;

    my @workers;
    my $num_threads = shift;
    my $dbname = shift;
    my $queue = new Thread::Queue;

    for (0..$num_threads-1) {
            $workers[$_] = new threads(\&worker);
                    print "TEST!\n";
    }

    while ($_ = shift @ARGV) {
            $queue->enqueue($_);
    }

    sub worker() {
            while ($file = $queue->dequeue) {
                    system ('./parser.pl', $dbname, $file);
            }
    }

    for (0..$num_threads-1) { $queue->enqueue(undef); }
    for (0..$num_threads-1) { $workers[$_]->join; }

Com alguns ajustes de luz, você pode alterar o número de threads, fornecer uma matriz de comandos, etc. Como isso acontece agora, ele leva o número de threads especificados na linha de comando, um nome de banco de dados e uma lista de arquivos para importar, em seguida, gera uma instância para cada arquivo executando o número especificado de uma só vez.

    
por 28.03.2012 / 09:26
0

ou ... você pode fazer assim:

threads=20
tempfifo=$PMS_HOME/$$.fifo

trap "exec 1000>&-;exec 1000<&-;exit 0" 2
mkfifo $tempfifo
exec 1000<>$tempfifo
rm -rf $tempfifo

for ((i=1; i<=$threads; i++))
do
    echo >&1000
done

for ((j=1; j<=1000; j++))
do
    read -u1000
    {
        echo $j
        echo >&1000
    } &
done

wait
echo "done!!!!!!!!!!"

todas as vezes, ele executa 20 threads em paralelo.

espero que ajude:)

    
por 28.12.2015 / 10:16

Tags