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 crd
de 300 a 9999999.
Si el shell cree que hay ranuras libres en la
threads
matriz, iniciará una nuevacli.php
utilizando los 4 procesos.De lo contrario, recorrerá aproximadamente 300 procesos para que el
kernel complete el/proc
sistema de archivos virtual y pruebe si
existe un directorio. Cualquier directorio faltante hará que las entradas se
eliminen de lathreads
matriz.
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.php
si 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.php
procesos, y el número está determinado por la velocidad de su máquina, el tiempo que cli.php
tarda 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 $pid
en lugar de [ ! -d "/proc/${pid}" ]
: kill -0
no elimina nada, pero devuelve un error si el proceso no existe. kill
es 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 threads
matriz.
Una segunda mejora reemplazaría la llamada al programa externo expr
con 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 labels
matriz.
Para hacer mucho más análisis necesitamos saber el tiempo aproximado que cli.php
tarda en ejecutarse y cuántas ejecuciones hay.
Como lo BUGS
dice 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 xargs
o parallel
. Con frecuencia prefiero usar make
. Lo primero es determinar cuántas copias cli.php
se quieren. Entonces un simple Makefile
como
%:
\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 make
incluir xargs
la no necesidad de tomar medidas excesivas para cancelar el procesamiento si cli.php devuelve errores.
xargos
Para una xargs
solució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 -nf
y 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