Eu tenho um monte de imagens PNG em um diretório. Eu tenho um aplicativo chamado pngout que eu corro para compactar essas imagens. Este aplicativo é chamado por um script que eu fiz. O problema é que esse script executa um de cada vez, algo como isto:
FILES=(./*.png)
for f in "${FILES[@]}"
do
echo "Processing $f file..."
# take action on each file. $f store current file name
./pngout -s0 $f R${f/\.\//}
done
Processar apenas um arquivo por vez, leva muito tempo. Depois de executar este aplicativo, vejo que a CPU é de apenas 10%. Então, descobri que posso dividir esses arquivos em 4 lotes, colocar cada lote em um diretório e disparar 4, de quatro janelas de terminal, quatro processos, para que eu tenha quatro instâncias do meu script, ao mesmo tempo, processando essas imagens e as o trabalho leva 1/4 do tempo.
O segundo problema é que perdi tempo dividindo as imagens e lotes e copiando o script para quatro diretórios, abrindo 4 janelas de terminal, bla bla ...
Como fazer isso com um script, sem ter que dividir nada?
Quero dizer duas coisas: primeiro, como faço a partir de um script bash, aciono um processo em segundo plano? (basta adicionar & ao final?) Segundo: como eu paro de enviar tarefas para segundo plano depois de enviar a quarta tarefa e coloco o script em espera até que as tarefas terminem? Quero dizer, apenas enviando uma nova tarefa para o plano de fundo quando uma tarefa termina, mantendo sempre quatro tarefas em paralelo? se eu não fizer isso, o loop disparará zilhões de tarefas em segundo plano e a CPU ficará obstruída.
fonte
Respostas:
Se você possui uma cópia
xargs
compatível com a execução paralela-P
, basta fazerPara outras idéias, o wiki do Wooledge Bash possui uma seção no artigo Gerenciamento de processos que descreve exatamente o que você deseja.
fonte
pngout
comando que o OP queria executar. A opção principal é-P 4
, que diz ao xargs para usar até 4 comandos simultâneos.printf
função aqui em vez de apenas regularls .. | grep .. *.png
? Também estava interessado nosxargs
parâmetros que você usou (-0
e-I{}
). Obrigado!ls
não podem ser usados para analisar nomes de arquivos de maneira portável e segura . Os únicos caracteres seguros a serem usados para delimitar nomes de arquivos são\0
e/
, já que todos os outros caracteres, inclusive\n
, podem fazer parte do próprio nome do arquivo. Osprintf
usos\0
para os nomes de arquivos delimitar, e os-0
informaxargs
deste. O-I{}
dizxargs
para substituir{}
com o argumento.Além das soluções já propostas, você pode criar um makefile que descreva como criar um arquivo compactado a partir de descompactado e usá-lo
make -j 4
para executar 4 trabalhos em paralelo. O problema é que você precisará nomear os arquivos compactados e descompactados de maneira diferente ou armazená-los em diretórios diferentes; caso contrário, será impossível escrever uma regra de fabricação razoável.fonte
Se você possui o GNU Parallel http://www.gnu.org/software/parallel/ instalado, você pode fazer isso:
Você pode instalar o GNU Parallel simplesmente:
Assista aos vídeos de introdução do GNU Parallel para saber mais: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
fonte
Para responder suas duas perguntas:
wait
comando, você pode pedir ao shell para aguardar a conclusão de todos os processos em segundo plano antes de prosseguir.Aqui está o script modificado para que
j
seja usado para acompanhar o número de processos em segundo plano. QuandoNB_CONCURRENT_PROCESSES
atingido, o script será redefinidoj
para 0 e aguardará a conclusão de todos os processos em segundo plano antes de retomar sua execução.fonte
$f
etc. (3) Use[
para scripts compatíveis com POSIX, mas para o bash puro[[
é sempre preferido. Nesse caso,((
é mais apropriado para a aritmética.