Secuencial: for i in {1..1000}; do do_something $i; done
demasiado lento
Paralelo: for i in {1..1000}; do do_something $i& done
- demasiada carga
¿Cómo ejecutar comandos en paralelo, pero no más de, por ejemplo, 20 instancias por momento?
Ahora usualmente usa hack like for i in {1..1000}; do do_something $i& sleep 5; done
, pero no es una buena solución
Actualización 2 : convirtió la respuesta aceptada en un script: http://vi-server.org/vi/parallel
#!/bin/bash
NUM=$1; shift
if [ -z "$NUM" ]; then
echo "Usage: parallel <number_of_tasks> command"
echo " Sets environment variable i from 1 to number_of_tasks"
echo " Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
exit 1
fi
export CMD="$@";
true ${MAKEOPTS:="-j20"}
cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})
all: \${jobs}
\${jobs}:
i=\$@ sh -c "\$\$CMD"
EOF
Tenga en cuenta que debe reemplazar 8 espacios con 2 pestañas antes de "i =" para que funcione.
parallel
en moreutils no es paralelo GNU y es bastante limitado en sus opciones. El comando anterior no se ejecutará con el paralelo desde moreutils.xargs --max-procs=20
.No es una solución bash, pero debe usar un Makefile, posiblemente con
-l
una carga máxima que no exceda.Luego, para comenzar 20 trabajos a la vez
o para iniciar tantos trabajos como sea posible sin exceder una carga de 5
fuente
echo -e 'PHONY=jobs\njobs=$(shell echo {1..100000})\n\nall: ${jobs}\n\n${jobs}:\n\t\techo $@; sleep `echo $$RANDOM/6553 | bc -l`' | make -f - -j20
Ahora se ve más hacky otra vez.publicar el script en la pregunta con formato:
Tenga en cuenta que debe reemplazar 8 espacios con 2 pestañas antes de "i =".
fuente
Una idea simple:
Verifique i modulo 20 y ejecute el comando de espera de shell antes de hacer algo.
fuente
Puede usar
ps
para contar cuántos procesos tiene en ejecución, y cada vez que esto cae por debajo de un cierto umbral, inicia otro proceso.Pseudocódigo:
fuente
fuente
while [ `jobs | wc -l` -ge 20]; do
?njobs
dos veces, y el rendimiento es bastante importante en shell scripts que las tareas de ejecución del sueño;)sleep 1
desleep 0.1
y empezar a njobs promedio de 40-50 en lugar de 20. Si hay más de 20 puestos de trabajo que tenemos que esperar a que cualquier trabajo se haya terminado, no sólo tiene que esperar 1 segundo.Puedes hacerlo así.
usando tuberías con nombre, cada vez, ejecuta 20 sub shell en paralelo.
Espero que ayude :)
fuente