
Eu criei um script que simplesmente executa outro processo em segundo plano que tenta controlar o número máximo de processos em execução (300 neste caso).
Inicialmente, ele executa scripts em aprox. 1-2 milissegundos, mas depois de várias horas de execução, ele acabará desacelerando em uma inclinação linear para 200ms - 350ms execs. Estou usando uma matriz para manter o PID #, mas também desativando a chave para reduzir o tamanho da tabela, mas tenho a sensação de que esse é o culpado.
#!/bin/bash
threads=()
threadcounter=0
crd=0;
while true;
do
threadcounter=${#threads[@]}
crdcounter=${#crds[@]}
if [ "$threadcounter" -lt 300 ]
then
s1=$(($(date +%s%N)/1000000))
pidf=$(/opt/remi/php/root/usr/bin/php cli.php initformula $crd >> /tmp/logger) &
pidfid=$!
s2=$(($(date +%s%N)/1000000))
echo "Init " $crd $(expr $s2 - $s1 ) "ms"
threads[$pidfid]+=$pidfid
else
for pid in "${!threads[@]}"; do
if [ ! -d "/proc/${pid}" ]
then
unset threads[$pid]
fi
done;
fi;
if [ "$crd" -gt 9999999 ]
then
echo "completed all";
exit;
fi;
crd=$(expr $crd + 1)
done;
Responder1
O código original.
Quando você começa, você apenas inicia 300 cópias do arquivo cli.php
. Isso leva cerca de 1.200 processos porque você deseja medir o tempo necessário para o lançamento.
Em seguida, você faz um loop na variável crd
de 300 a 9999999.
Se o shell achar que há slots extras no
threads
array, ele iniciará um novocli.php
usando os 4 processos.Caso contrário, você fará um loop em aproximadamente 300 processos, fazendo com que o
kernel preencha o/proc
sistema de arquivos virtual e testando se
existe um diretório. Quaisquer diretórios ausentes farão com que as entradas sejam
excluídas dathreads
matriz.
Você tem um array não utilizado chamado crds
.
Porque após os 300 iniciais, cada loop da variável crd criará 1 nova cópia cli.php
se houver slots livres na tabela de processos, mas poderá remover até 300 se a tabela estiver cheia, no final da execução só sabíamos que entre 300 e cerca de 9.967.000 cli.php
processos foram iniciados, sendo o número determinado pela velocidade da sua máquina, quanto tempo cli.php
leva para ser executado e a carga na máquina. 6 ordens de magnitude é muito para otimizar!
Uma regra prática é que, em uma máquina moderna, a inicialização de 1 processo leva 1 ms em um núcleo, portanto, você não está se saindo mal em sua taxa de inicialização inicial. Eu esperaria uma alteração significativa na taxa de lançamento quando você ficar sem núcleos livres para lançar novos processos.
Melhorias
Uma maneira de acelerar isso seria usar ! kill -0 $pid
em vez de [ ! -d "/proc/${pid}" ]
- kill -0
não mata nada, mas retorna um erro se o processo não existir. kill
é um shell embutido (como está [
), mas a quantidade de trabalho que o kernel precisa realizar é menor. Isto será mais eficaz se na maioria das vezes não houver slots livres na threads
matriz.
Uma segunda melhoria substituiria a chamada para o programa externo expr
pelo uso da aritmética interna $(( ... ))
, reduzindo assim a sobrecarga de iniciar uma cópia do cli.php
. Isto é mais eficaz se na maioria das vezes houver slots livres na labels
matriz.
Para fazer muito mais análises, precisamos saber o tempo aproximado que cli.php
leva para ser executado e quantas execuções existem.
Como BUGS
diz a seção do manual do bash, It's too big and too slow.
é certamente possível que haja espaço para melhorar a implementação do array no bash.
Implementações Alternativas
fazer
Nos comentários sugere-se usar xargs
ou parallel
. Frequentemente prefiro usar make
. A primeira coisa é determinar quantas cópias cli.php
são desejadas. Então um simples Makefile
como
%:
\t/opt/remi/php/root/usr/bin/php cli.php initformula $@
onde \t é um caractere de tabulação. (Esta versão simples pressupõe que você não possui nenhum arquivo com nomes numéricos no intervalo de 0 a 9999999). Então invoque make as
make -O -j 300 $(seq 0 9999999) > /tmp/logger
se você quiser as 10.000.000 invocações cli.php completas. Razões pelas quais prefiro make
incluir xargs
a não necessidade de tomar medidas excessivas para abortar o processamento se cli.php retornar erros.
xargs
Para uma xargs
solução tente
seq 0 9999999 | xargs -n 1 -P 300 /opt/remi/php/root/usr/bin/php cli.php initformula > /tmp/logger
o que é mais simples.
Bash
No entanto, uma solução Bash que usa wait -nf
e não se preocupa em rastrear os PIDs pode ser mais do agrado do OP. Ele inicia os 300 processos iniciais e, ao detectar um deles terminando, iniciará outro. Uma vez iniciado o 10.000.000, ele faz uma espera final para deixar todos os trabalhos terminarem. Não é exatamente o mesmo algoritmo, mas muito próximo.
#!/bin/bash
for(crd=0;crd<300;crd++); do
/opt/remi/php/root/usr/bin/php cli.php initformula $crd &
done > /tmp/logger
for(;crd<=9999999;crd++); do
wait -fn
/opt/remi/php/root/usr/bin/php cli.php initformula $crd &
done >> /tmp/logger
wait