Tengo un montón de imágenes PNG en un directorio. Tengo una aplicación llamada pngout que ejecuto para comprimir estas imágenes. Esta aplicación es llamada por un script que hice. El problema es que este script hace uno a la vez, algo como esto:
FILES=(./*.png)
for f in "${FILES[@]}"
do
echo "Processing $f file..."
# take action on each file. $f store current file name
./pngout -s0 $f R${f/\.\//}
done
Procesar solo un archivo a la vez, lleva mucho tiempo. Después de ejecutar esta aplicación, veo que la CPU es solo del 10%. Entonces descubrí que puedo dividir estos archivos en 4 lotes, poner cada lote en un directorio y disparar 4, desde cuatro ventanas de terminal, cuatro procesos, por lo que tengo cuatro instancias de mi script, al mismo tiempo, procesando esas imágenes y el El trabajo toma 1/4 del tiempo.
El segundo problema es que perdí el tiempo dividiendo las imágenes y lotes y copiando el script en cuatro directorios, abriendo 4 ventanas de terminal, bla bla ...
¿Cómo hacer eso con un script, sin tener que dividir nada?
Me refiero a dos cosas: primero, ¿cómo hago desde un script bash, disparo un proceso a un segundo plano? (¿solo agregar & al final?) Segundo: ¿cómo dejo de enviar tareas a un segundo plano después de enviar las cuartas tareas y pongo el script en espera hasta que finalicen las tareas? Quiero decir, ¿simplemente enviar una nueva tarea a un segundo plano cuando finaliza una tarea, manteniendo siempre 4 tareas en paralelo? si no lo hago, el bucle disparará millones de tareas a un segundo plano y la CPU se obstruirá.
fuente
Respuestas:
Si tiene una copia de la
xargs
que es compatible con la ejecución paralela-P
, simplemente puede hacerPara otras ideas, el wiki de Wooledge Bash tiene una sección en el artículo de Gestión de Procesos que describe exactamente lo que desea.
fuente
pngout
comando que el OP quería ejecutar. La opción clave es-P 4
, que le dice a xargs que use hasta 4 comandos simultáneos.printf
función aquí en lugar de solo regularls .. | grep .. *.png
? También estaba interesado en losxargs
parámetros que usaste (-0
y-I{}
). ¡Gracias!ls
no se pueden usar para analizar nombres de archivo de forma portátil y segura . Los únicos caracteres seguros que se pueden usar para delimitar nombres de archivos son\0
y/
, dado que cualquier otro carácter, incluido\n
, puede ser parte del nombre del archivo. Losprintf
usos\0
a los nombres de archivo y los delimitan,-0
informaxargs
de ello. El-I{}
le dicexargs
a reemplazar{}
con el argumento.Además de las soluciones ya propuestas, puede crear un archivo MAKE que describa cómo hacer un archivo comprimido sin comprimir y usar
make -j 4
para ejecutar 4 trabajos en paralelo. El problema es que necesitará nombrar los archivos comprimidos y sin comprimir de manera diferente, o almacenarlos en diferentes directorios, de lo contrario será imposible escribir una regla de creación razonable.fuente
Si tiene GNU Parallel http://www.gnu.org/software/parallel/ instalado , puede hacer esto:
Puede instalar GNU Parallel simplemente por:
Mire los videos de introducción de GNU Parallel para obtener más información: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
fuente
Para responder a sus dos preguntas:
wait
comando, puede pedirle al shell que espere a que finalicen todos los procesos en segundo plano antes de continuar.Aquí está el script modificado para que
j
se use para realizar un seguimiento de la cantidad de procesos en segundo plano. CuandoNB_CONCURRENT_PROCESSES
se alcanza, el script se restableceráj
a 0 y esperará a que finalicen todos los procesos en segundo plano antes de reanudar su ejecución.fuente
$f
etc. (3) Uso[
para scripts compatibles con POSIX, pero[[
siempre se prefiere para bash puro . En este caso,((
es más apropiado para la aritmética.