Veja mais ou menos como resolvi o mesmo problema em um ambiente em que parallel
não estava disponível. Isso depende de recursos bash, então você precisa de #!/bin/bash
ou explicitamente executando o script através do bash.
MAX_CONCURRENT=50
n=0
some_command_that_outputs_urls \
| while read url
do
{
do_something_with $url
} &
PIDS="$PIDS $!"
((++n))
if test "$n" -ge "$MAX_CONCURRENT"
then
n=0
wait $PIDS
PIDS=""
fi
done
test -n "$PIDS" && wait $PIDS
Você pode ajustar $MAX_CONCURRENT
para especificar o número máximo de segmentos desejado (aproximado). E, claro, você substituirá some_command_that_outputs_urls
e do_something_with $url
pelo que for apropriado em seu cenário. Por exemplo, você pode substituir a linha some_command_that_outputs_urls \
por
for i in {0800..9999}; do
for j in {001..032}; do
printf 'http://example.com/%s-%s.jpg\n' $i $j
done
done \
# ...| while read url ...
e do_something_with $url
simplesmente com
wget $url
dando-lhe o resultado final
MAX_CONCURRENT=50
n=0
for i in {0800..9999}; do
for j in {001..032}; do
printf 'http://example.com/%s-%s.jpg\n' $i $j
done
done \
| while read url
do
{
wget $url
} &
PIDS="$PIDS $!"
((++n))
if test "$n" -ge "$MAX_CONCURRENT"
then
n=0
wait $PIDS
PIDS=""
fi
done
test -n "$PIDS" && wait $PIDS
A maneira como isso funciona é ter um comando que gera a lista de URLs (neste caso) em sua saída padrão, e ler uma linha por vez no loop while
(atente para novas linhas!). Ele gerará até $MAX_CONCURRENT
processos simultâneos, usando $n
para rastrear quantos foram gerados e $PIDS
para registrar seus IDs de processo. Uma vez que $MAX_CONCURRENT
processos tenham sido gerados (note que o que realmente está sendo criado é uma instrução composta, então você pode ter vários comandos e até mesmo blocos dentro dele), wait
nos PIDs gerados (isso retorna imediatamente se nenhum dos PIDs especificados ainda estão sendo executados) e redefinir seu estado interno e, em seguida, prosseguir com outra execução.
Existem várias maneiras de melhorar esse script, incluindo o melhor tratamento de PIDs reutilizadas, mas ele faz o trabalho que eu queria que ele fizesse no ambiente em que ele precisava ser executado, então é bom o suficiente para mim. Na minha versão atual, há também um tempo limite no local e ele é executado novamente regularmente por meio do cron, portanto, o risco de tempos de execução descontrolados é muito reduzido em comparação com essa versão mais simples.