Em um sistema GNU e, se houver pv
, você pode fazer:
cmd='
that command | to execute &&
as shell code'
yes | pv -qL10 | xargs -n1 -P20 sh -c "$cmd" sh
O -P20
é executar no máximo 20 $cmd
ao mesmo tempo.
-L10
limita a taxa a 10 bytes por segundo, portanto, 5 linhas por segundo.
Se seus $cmd
s se tornarem lentos e fizer com que o limite de 20 seja atingido, a xargs
leitura será interrompida até que $cmd
pelo menos uma instância retorne. pv
ainda continuará gravando no pipe na mesma taxa, até que o pipe fique cheio (o que no Linux com um tamanho de pipe padrão de 64KiB levará quase 2 horas).
Nesse ponto, pv
parará de escrever. Mas mesmo assim, quando xargs
retomar a leitura, pv
tentará recuperar e enviar todas as linhas que deveria ter enviado mais cedo o mais rápido possível, para manter uma média geral de 5 linhas por segundo.
O que isso significa é que, contanto que seja possível, com 20 processos, atender a 5 rodadas por segundo no requisito médio, isso será feito. No entanto, quando o limite é atingido, a taxa na qual novos processos são iniciados não será conduzida pelo timer do pv, mas pela taxa na qual as instâncias anteriores do cmd retornam. Por exemplo, se 20 estão em execução no momento e duram 10 segundos, e 10 deles decidem terminar todos ao mesmo tempo, 10 novos serão iniciados ao mesmo tempo.
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 zsh
se o seu sleep
comando suportar segundos fracionários):
typeset -F SECONDS=0
n=0; while true; do
your-command &
sleep "$((++n * 0.2 - SECONDS))"
done
Isso não vincula o número de your-command
s concorrentes .