A mínima Tarefa "Fila" com estoque Linux ferramentas para alavancar CPU Multicore
-
06-07-2019 - |
Pergunta
Qual é a melhor/mais fácil forma de criar um mínimo de tarefa de sistema de fila para Linux com bash e ferramentas comuns?
Eu tenho um arquivo com 9'000 linhas, cada linha tem um comando de linha de comando, os comandos são completamente independentes.
command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log
...
Minha caixa tem mais de um núcleo e quero executar X tarefas ao mesmo tempo.Eu procurei na web para uma boa maneira de fazer isso.Aparentemente, muitas pessoas têm este problema, mas ninguém tem uma boa solução até agora.
Seria bom se a solução tinha as seguintes características:
- pode interpretar mais de um comando (por exemplo,
command; command
) - pode interpretar o fluxo de redirecionamentos nas linhas (por exemplo,
ls > /tmp/ls.txt
) - utiliza apenas ferramentas comuns no Linux
Pontos de bônus se ele funciona em outros Unix-clones sem muito exótica requisitos.
Solução
Você pode converter sua lista de comando em um Makefile? Nesse caso, você pode simplesmente executar "Make -j X".
Outras dicas
GNU paralelo http://www.gnu.org/software/parallel/ é uma ferramenta mais geral para paralelizante que o PPSS.
Se o Runfile contiver:
command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log
você pode fazer:
cat runfile | parallel -j+0
que executará um comando por núcleo da CPU.
Se seus comandos forem tão simples quanto acima, você nem precisará de runfile, mas pode fazer:
seq 1 3 | parallel -j+0 'command {} > Logs/{}.log'
Se você tiver mais computadores disponíveis para fazer o processamento, poderá olhar para as opções - -SSHLOGIN e - -TRC para o GNU paralelo.
Ok, depois de postar a pergunta aqui, encontrei o seguinte projeto que parece promissor: PPSS.
EDIT: Não é exatamente o que eu quero, o PPSS está focado no processamento de "todos os arquivos no diretório A".
Bem, este é um tipo de diversão questão de qualquer maneira.
Aqui está o que eu faria, assumindo bash(1) do curso.
- descobrir como muitos destes comandos pode ser útil executar em simultâneo.Não vai ser apenas o número de núcleos;um monte de comandos será suspenso e/S e esse tipo de coisa.Ligar para o número N.
N=15
por exemplo. - montar uma armadilha processador de sinal para o sinal SIGCHLD, que ocorre quando uma criança de processo termina.
trap signalHandler SIGCHLD
- cat sua lista de comandos dentro de um tubo
- escrever um ciclo que se lê do stdin e executa os comandos, um por um, diminuindo um contador.Quando o contador for 0,
wait
s. - seu processador de sinal, que é executado no SIGCHLD, incrementos de esse contador.
Então, agora, corre-se o primeiro N
comandos e, em seguida, aguarda.Quando o primeiro filho termina, a espera de retorno, lê-se outra linha, é executado um comando novo, e espera novamente.
Agora, este é um caso que cuida de muitos trabalhos para terminar juntos.Eu suspeito você pode começar com uma versão mais simples:
N=15
COUNT=N
cat mycommands.sh |
while read cmd
do
eval $cmd &
if $((count-- == 0))
then
wait
fi
od
Agora, este irá iniciar os primeiros 15 comandos e, em seguida, execute o resto uma vez que alguns de comando termina.
Diversão de computação distribuída semelhante é o script MapReduce Bash:
http://blog.last.fm/2009/04/06/mapreduce-bash-script
E obrigado por apontar o PPSS!
Você pode usar o Xargs comando, é -Max-Procs faz o que você quer. Por exemplo, a solução Charlie Martin se torna com XARGS:
tr '\012' '\000' <mycommands.sh |xargs --null --max-procs=$X bash -c
detalhes:
- X é o número de processos máx. Por exemplo: x = 15. -Max-Procs está fazendo a mágica
- O primeiro TR está aqui para rescindir linhas por bytes nulos para XARGS -NULL opção para que as citações de redirecionamento etc.
- Bash -C executa o comando
Eu testei com este arquivo myCommands.sh, por exemplo:
date
date "+%Y-%m-%d" >"The Date".txt
wc -c <'The Date'.txt >'The Count'.txt
Este é um caso específico, mas se você estiver tentando processar um conjunto de arquivos e produzir outro conjunto de arquivos de saída, poderá iniciar o número de processos #Cores e verificar se existe um arquivo de saída antes de processá -lo. O exemplo abaixo converte um diretório de arquivos .m4b em arquivos .mp3:
Basta executar este comando quantas vezes você tem núcleos:
ls *m4b | enquanto lido f; Teste -f $ {f%m4b} mp3 || mencoder -Of Rawaudio "$ f" -oac mp3Lame -ovc cópia -o $ {f%m4b} mp3; feito &
Você pode ver minha fila de tarefas escritas no Bash: https://github.com/pavelpat/yastq
Fila de tarefas + paralelo + adição dinâmica
Usando um FIFO, esse script em si para processar a fila. Dessa forma, você pode adicionar comandos à fila em tempo real (quando a fila já estiver iniciada).
Uso: ./Queue Command [# of Children] [Nome da fila
Exemplo, com 1 thread:
./queue "sleep 5; echo ONE" ./queue "echo TWO"
Resultado:
ONE TWO
Exemplo, com 2 thread:
./queue "sleep 5; echo ONE" 2 ./queue "echo TWO"
Resultado:
TWO ONE
Exemplo, com 2 filas:
./queue "sleep 5; echo ONE queue1" 1 queue1 ./queue "sleep 3; echo ONE queue2" 1 queue2
Resultado:
ONE queue2 ONE queue1
O script (salve -o como "fila" e chmod +x fila):
#!/bin/bash #Print usage [[ $# -eq 0 ]] && echo Usage: $0 Command [# of children] [Queue name] && exit #Param 1 - Command to execute COMMAND="$1" #Param 2 - Number of childs in parallel MAXCHILD=1 [[ $# -gt 1 ]] && MAXCHILD="$2" #Param 3 - File to be used as FIFO FIFO="/tmp/defaultqueue" [[ $# -gt 2 ]] && FIFO="$3" #Number of seconds to keep the runner active when unused TIMEOUT=5 runner(){ #Associate file descriptor 3 to the FIFO exec 3"$FIFO" while read -u 3 -t $TIMEOUT line; do #max child check while [ `jobs | grep Running | wc -l` -ge "$MAXCHILD" ]; do sleep 1 done #exec in backgroud (eval "$line")& done rm $FIFO } writer(){ #fork if the runner is not running lsof $FIFO >/dev/null || ($0 "QueueRunner" "$MAXCHILD" "$FIFO" &) #send the command to the runner echo "$COMMAND" > $FIFO } #Create the FIFO file [[ -e "$FIFO" ]] || mkfifo "$FIFO" #Start the runner if in the runner fork, else put the command in the queue [[ "$COMMAND" == "QueueRunner" ]] && runner || writer