Em um sistema GNU e se você tiver pv
, você poderia fazer:
cmd='
that command | to execute &&
as shell code'
yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
O -P20
é para executar no máximo 20 $cmd
ao mesmo tempo.
-L10
limita a taxa a 10 bytes por segundo, portanto, 5 linhas por segundo.
Se o $cmd
s se tornar dois lento e fizer com que o limite 20 seja atingido, xargs
parará de ler até que pelo menos uma $cmd
instância retorne. pv
ainda continuará escrevendo para o pipe na mesma taxa, até que o pipe fique cheio (o que no Linux com um tamanho padrão de 64KiB levará quase 2 horas).
Nesse momento, pv
deixará de ser escrito. Mas, mesmo assim, quando xargs
retomar a leitura, pv
tentará recuperar e enviar todas as linhas que deveria ter enviado antes o mais rápido possível, de modo a manter uma média global de 5 linhas por segundo.
O que isso significa é que, contanto que seja possível, com 20 processos atender a essa exigência média de 5 execuções por segundo, ele fará isso. No entanto, quando o limite é atingido, a taxa na qual novos processos são iniciados não será acionada pelo temporizador de pv, mas pela taxa na qual as instâncias de cmd anteriores retornam. Por exemplo, se 20 estão atualmente em execução e foram por 10 segundos, e 10 deles decidem terminar tudo ao mesmo tempo, então 10 novos serão iniciados de uma vez.
Exemplo:
$ cmd='date +%T.%N; exec sleep 2'
$ yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
09:49:23.347013486
09:49:23.527446830
09:49:23.707591664
09:49:23.888182485
09:49:24.068257018
09:49:24.338570865
09:49:24.518963491
09:49:24.699206647
09:49:24.879722328
09:49:25.149988152
09:49:25.330095169
Em média, será 5 vezes por segundo, mesmo que o atraso entre duas execuções nem sempre seja exatamente de 0,2 segundos.
Com ksh93
(ou com zsh
se o comando sleep
suportar frações de segundo):
typeset -F SECONDS=0
n=0; while true; do
your-command &
sleep "$((++n * 0.2 - SECONDS))"
done
Isso não impõe limite ao número de your-command
s simultâneos.