El código original.

El código original.

Se me ocurrió un script que simplemente ejecuta otro proceso en segundo plano que intenta controlar la cantidad máxima de procesos en ejecución (300 en este caso).

Inicialmente ejecuta scripts a aprox. 1-2 milisegundos, pero después de varias horas de funcionamiento eventualmente disminuirá en una pendiente lineal a 200 ms - 350 ms ejecutivos. Estoy usando una matriz para mantener el número de PID pero también desarmado la clave para reducir el tamaño de la tabla, pero tengo la sensación de que ese es el culpable.

#!/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;

Respuesta1

El código original.

Cuando empiezas, simplemente empiezas con 300 copias de cli.php. Esto requiere alrededor de 1200 procesos porque desea medir el tiempo necesario para el lanzamiento.

Luego, repite la variable crdde 300 a 9999999.

  • Si el shell cree que hay ranuras libres en la threadsmatriz, iniciará una nueva cli.phputilizando los 4 procesos.

  • De lo contrario, recorrerá aproximadamente 300 procesos para que el
    kernel complete el /procsistema de archivos virtual y pruebe si
    existe un directorio. Cualquier directorio faltante hará que las entradas se
    eliminen de la threadsmatriz.

Tienes una matriz no utilizada llamada crds.

Porque después de los 300 iniciales, cada bucle de la variable crd creará 1 nueva copia cli.phpsi hay espacios libres en la tabla de procesos, pero puede eliminar hasta 300 si la tabla está llena, al final de la ejecución solo sabíamos que Se han iniciado entre 300 y aproximadamente 9.967.000 cli.phpprocesos, y el número está determinado por la velocidad de su máquina, el tiempo que cli.phptarda en ejecutarse y la carga de la máquina. ¡6 órdenes de magnitud es mucho para optimizar!

Una regla general es que en una máquina moderna, iniciar 1 proceso requiere 1 ms en un núcleo, por lo que no le está yendo mal con su velocidad de lanzamiento inicial. Yo esperaría un problema significativo en la tasa de lanzamiento una vez que se quede sin núcleos libres para iniciar nuevos procesos.

Mejoras

Una forma de acelerar esto sería usar ! kill -0 $piden lugar de [ ! -d "/proc/${pid}" ]: kill -0no elimina nada, pero devuelve un error si el proceso no existe. killes un shell incorporado (tal como está [), pero la cantidad de trabajo que tiene que hacer el kernel es menor. Esto será más efectivo si la mayor parte del tiempo no hay espacios libres en la threadsmatriz.

Una segunda mejora reemplazaría la llamada al programa externo exprcon el uso de la aritmética incorporada $(( ... )), reduciendo así la sobrecarga de ejecutar una copia de cli.php. Esto es más efectivo si la mayor parte del tiempo hay espacios libres en la labelsmatriz.

Para hacer mucho más análisis necesitamos saber el tiempo aproximado que cli.phptarda en ejecutarse y cuántas ejecuciones hay.

Como lo BUGSdice la sección del manual de bash It's too big and too slow., es ciertamente posible que exista margen para mejorar la implementación de la matriz en bash.

Implementaciones alternativas

hacer

En los comentarios se sugiere utilizar xargso parallel. Con frecuencia prefiero usar make. Lo primero es determinar cuántas copias cli.phpse quieren. Entonces un simple Makefilecomo

%:
\t/opt/remi/php/root/usr/bin/php cli.php initformula $@

donde \t es un carácter de tabulación. (Esta versión simple supone que no tiene ningún archivo con nombres numéricos en el rango de 0 a 9999999). Luego invoca make as

make -O -j 300 $(seq 0 9999999) > /tmp/logger

si desea las 10.000.000 invocaciones completas de cli.php. Razones por las que prefiero makeincluir xargsla no necesidad de tomar medidas excesivas para cancelar el procesamiento si cli.php devuelve errores.

xargos

Para una xargssolución prueba

seq 0 9999999 | xargs -n 1 -P 300 /opt/remi/php/root/usr/bin/php cli.php initformula > /tmp/logger

que es más sencillo.

Intento

Sin embargo, una solución Bash que utiliza wait -nfy no se preocupa en absoluto por el seguimiento de los PID podría ser más del gusto del OP. Inicia los 300 procesos iniciales y, cuando detecta que uno de ellos finaliza, iniciará otro. Una vez que se ha iniciado el número 10.000.000, se realiza una espera final para dejar que finalicen todos los trabajos. No es exactamente el mismo algoritmo pero sí muy parecido.

#!/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

información relacionada