O código original.

O código original.

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 crdde 300 a 9999999.

  • Se o shell achar que há slots extras no threadsarray, ele iniciará um novo cli.phpusando os 4 processos.

  • Caso contrário, você fará um loop em aproximadamente 300 processos, fazendo com que o
    kernel preencha o /procsistema de arquivos virtual e testando se
    existe um diretório. Quaisquer diretórios ausentes farão com que as entradas sejam
    excluídas da threadsmatriz.

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.phpse 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.phpprocessos foram iniciados, sendo o número determinado pela velocidade da sua máquina, quanto tempo cli.phpleva 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 $pidem vez de [ ! -d "/proc/${pid}" ]- kill -0nã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 threadsmatriz.

Uma segunda melhoria substituiria a chamada para o programa externo exprpelo 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 labelsmatriz.

Para fazer muito mais análises, precisamos saber o tempo aproximado que cli.phpleva para ser executado e quantas execuções existem.

Como BUGSdiz 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 xargsou parallel. Frequentemente prefiro usar make. A primeira coisa é determinar quantas cópias cli.phpsão desejadas. Então um simples Makefilecomo

%:
\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 makeincluir xargsa não necessidade de tomar medidas excessivas para abortar o processamento se cli.php retornar erros.

xargs

Para uma xargssoluçã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 -nfe 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

informação relacionada