Pergunta

Estou tentando executar alguns comandos em paralelo, em segundo plano, usando o Bash. Aqui está o que estou tentando fazer:

forloop {
  //this part is actually written in perl
  //call command sequence
  print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}

A parte entre os backsticks (``) gera um novo shell e executa os comandos em sucessão. O problema é que o controle do programa original retorna somente após a execução do último comando. Gostaria de executar toda a declaração em segundo plano (não estou esperando nenhum valores de saída/retorno) e gostaria que o loop continuasse em execução.

O programa de chamada (aquele que tem o loop) não terminaria até que todas as conchas geradas terminem.

Eu poderia usar tópicos no Perl para gerar diferentes tópicos que chamam de conchas diferentes, mas parece um exagero ...

Posso iniciar um shell, dar um conjunto de comandos e pedir para ir ao fundo?

Foi útil?

Solução

Eu não testei isso, mas que tal

print `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;

Os parênteses significam executar em uma sub -Shell, mas isso não deve doer.

Outras dicas

Obrigado Hugh, isso fez isso:

adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
adrianp@frost:~$ stopped

[1]+  Done                    ( echo "started"; sleep 15; echo "stopped" )
adrianp@frost:~$ 

As outras idéias não funcionam porque iniciam cada comando em segundo plano, e não a sequência de comando (o que é importante no meu caso!).

Obrigado novamente!

Outra maneira é usar a seguinte sintaxe:

{ command1; command2; command3; } &
wait

Observe que o & Vai no final do grupo de comando, não após cada comando. O semicolon após o comando final é necessário, assim como o espaço após o primeiro suporte e antes do suporte final. o wait No final, garante que o processo pai não seja morto antes que o processo infantil gerado (o grupo de comando) termine.

Você também pode fazer coisas sofisticadas como redirecionar stderr e stdout:

{ command1; command2; command3; } 2>&2 1>&1 &

Seu exemplo seria:

forloop() {
    { touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end
for command in $commands
do
    "$command" &
done
wait

O ampers e no final do comando o executa em segundo plano, e o wait aguarda até que a tarefa em segundo plano seja concluída.

Gavincattell Cheguei ao mais próximo (para Bash, IMO), mas, como Mad_ady apontou, ele não lidava com os arquivos "Lock". Isto deveria:

Se houver outros trabalhos pendentes, o esperar Vou esperar por isso também. Se você precisar esperar por As cópias, você pode acumular esses PIDs e esperar apenas por eles. Caso contrário, você pode excluir as 3 linhas com "PIDs", mas é mais geral.

Além disso, adicionei verificação para evitar completamente a cópia:

pids=
for file in bigfile*
do
    # Skip if file is not newer...
    targ=/destination/$(basename "${file}")
    [ "$targ" -nt "$file" ] && continue

    # Use a lock file:  ".fileN.lock" for each "bigfileN"
    lock=".${file##*/big}.lock"
    ( touch $lock; cp "$file" "$targ"; rm $lock ) &
    pids="$pids $!"
done
wait $pids

Aliás, parece que você está copiando novos arquivos para um repositório FTP (ou similar). Se sim, você poderia Considere uma estratégia de cópia/renomeação em vez dos arquivos de bloqueio (mas esse é outro tópico).

A instalação em Bash que você está procurando é chamada Compound Commands. Veja a página do homem para obter mais informações:

Comandos compostos Um comando composto é um dos seguintes:

   (list) list  is  executed  in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below).  Variable assignments and
          builtin commands that affect the shell's environment do not remain in effect after  the  command  completes.   The
          return status is the exit status of list.

   { list; }
          list  is  simply  executed in the current shell environment.  list must be terminated with a newline or semicolon.
          This is known as a group command.  The return status is the exit status of list.  Note that unlike the metacharac‐
          ters  (  and  ),  {  and  } are reserved words and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from list by whitespace or another shell  metacharac‐
          ter.

Existem outros, mas esses são provavelmente os dois tipos mais comuns. O primeiro, The Parens, executará uma lista de comando em série em uma subshell, enquanto a segunda, os aparelhos encaracolados, terá uma lista de comandos em série no shell atual.

parens

% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013

aparelho encaracolado

% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013

Execute o comando usando um Job:

# date
# jue sep 13 12:43:21 CEST 2012
# at 12:45
warning: commands will be executed using /bin/sh
at> command1
at> command2
at> ...
at> CTRL-d
at> <EOT>
job 20 at Thu Sep 13 12:45:00 2012

O resultado será enviado para sua conta por correio.

Eu tropecei neste tópico aqui e decidi montar um trecho de código para gerar declarações acorrentadas como trabalhos de fundo. Eu testei isso no Bash para Linux, Ksh para IBM Aix e Busybox's Ash para Android, então acho que é seguro dizer que funciona algum Concha semelhante a Bourne.

processes=0;
for X in `seq 0 10`; do
   let processes+=1;
   { { echo Job $processes; sleep 3; echo End of job $processes; } & };
   if [[ $processes -eq 5 ]]; then
      wait;
      processes=0;
   fi;
done;

Este código executa uma série de trabalhos em segundo plano até um certo limite de trabalhos simultâneos. Você pode usar isso, por exemplo, para recomendar muitos arquivos gzippeados com xz sem ter um grande monte de xz Processos comem toda a sua memória e fazem seu computador vomitar: neste caso, você usa * Enquanto o fora lista e o trabalho em lote seriam gzip -cd "$X" | xz -9c > "${X%.gz}.xz".

Execute os comandos em uma subshell:

(command1 ; command2 ; command3) &

Tente colocar comandos em aparelhos encaracolados com & s, assim:

{command1 & ; command2 & ; command3 & ; }

Isso não cria uma sub-concha, mas executa o grupo de comandos em segundo plano.

Hth

Não sei por que ninguém respondeu com a solução adequada:

my @children;
for (...) {
    ...
    my $child = fork;
    exec "touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;" if $child == 0;
    push @children, $child;
}
# and if you want to wait for them to finish,
waitpid($_) for @children;

Isso faz com que a Perl gere as crianças que executem cada comando e permite que você espere que todas as crianças se concluam antes de prosseguir.

A propósito,

print `some command`

e

system "some command"

emitir o mesmo conteúdo para stdout, mas o primeiro tem uma sobrecarga mais alta, pois Perl precisa capturar tudo "some command"SAUT

Bifurcando em um loop:

for i in x; do ((a; b; c;)&); done

Exemplo:

for i in 500 300 100; do ((printf "Start $i: "; date; dd if=/dev/zero of=testfile_$i bs=1m count=$i 2>/dev/null; printf "End $i: "; date;)&) && sleep 1; done

Apenas para o caso de alguém ainda estar interessado, você pode fazê -lo sem ligar para uma subshell como esta:

print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;

Você pode usar gnu parallel comando para executar trabalhos em paralelo. É mais seguro é mais rápido.

Meu palpite é que você está tentando copiar vários arquivos grandes de origem para destino. E por isso você pode fazer isso em paralelo com a declaração abaixo.

$ ls *|parallel -kj0 --eta 'cp {} /tmp/destination'

Como usamos -j0 Opção, todos os arquivos serão copiados em paralelo. Caso você precise reduzir o número de processos paralelos, poderá usar -j<n> Onde <n> é o número de processo paralelo a ser executado.

O paralelo também coletará a saída do processo e o relatará de maneira seqüencial (com -k opção) qual outro mecanismo de controle de trabalho não pode fazer.

--eta A opção fornecerá as estatísticas de detalhes do processo que está acontecendo. Portanto, podemos saber como maio do processo foi concluído e quanto tempo levará para terminar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top