J'ai un tas d'images PNG sur un répertoire. J'ai une application appelée pngout que je lance pour compresser ces images. Cette application est appelée par un script que j'ai fait. Le problème est que ce script fait un à la fois, quelque chose comme ceci:
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
Le traitement d'un seul fichier à la fois prend beaucoup de temps. Après avoir exécuté cette application, je constate que le CPU n'est que de 10%. J'ai donc découvert que je pouvais diviser ces fichiers en 4 lots, placer chaque lot dans un répertoire et en lancer 4, à partir de quatre fenêtres de terminal, quatre processus, donc j'ai quatre instances de mon script, en même temps, le traitement de ces images et la le travail prend 1/4 du temps.
Le deuxième problème est que j'ai perdu du temps à diviser les images et les lots et à copier le script dans quatre répertoires, ouvrir 4 fenêtres de terminal, bla bla ...
Comment faire avec un script, sans avoir à diviser quoi que ce soit?
Je veux dire deux choses: d'abord comment puis-je, à partir d'un script bash, déclencher un processus en arrière-plan? (ajoutez simplement & à la fin?) Deuxièmement: comment puis-je arrêter d'envoyer des tâches en arrière-plan après avoir envoyé les quatrièmes tâches et mettre le script en attente jusqu'à la fin des tâches? Je veux dire, envoyer simplement une nouvelle tâche en arrière-plan à la fin d'une tâche, en gardant toujours 4 tâches en parallèle? si je ne le fais pas, la boucle déclenchera des millions de tâches en arrière-plan et le CPU se bouchera.
la source
Réponses:
Si vous en avez une copie
xargs
qui prend en charge l'exécution parallèle avec-P
, vous pouvez simplement fairePour d'autres idées, le wiki Wooledge Bash a une section dans l'article Gestion des processus décrivant exactement ce que vous voulez.
la source
pngout
commande que l'OP voulait exécuter. L'option clé est-P 4
, qui indique à xargs d'utiliser jusqu'à 4 commandes simultanées.printf
fonction ici plutôt que simplement régulièrels .. | grep .. *.png
? J'ai également été intéressé par lesxargs
paramètres que vous avez utilisés (-0
et-I{}
). Merci!ls
ne peuvent pas être utilisés pour analyser les noms de fichiers de manière portative et en toute sécurité . Les seuls caractères sûrs à utiliser pour délimiter les noms de fichiers sont\0
et/
, puisque tous les autres caractères, y compris\n
, peuvent faire partie du nom de fichier lui-même. Lesprintf
utilisations\0
pour délimiter les noms de fichiers, et les-0
informexargs
de cela. Le-I{}
ditxargs
de remplacer{}
par l'argument.En plus des solutions déjà proposées, vous pouvez créer un makefile qui décrit comment créer un fichier compressé à partir d'un fichier non compressé, et l'utiliser
make -j 4
pour exécuter 4 travaux en parallèle. Le problème est que vous devrez nommer les fichiers compressés et non compressés différemment, ou les stocker dans des répertoires différents, sinon il sera impossible d'écrire une règle de création raisonnable.la source
Si vous avez GNU Parallel http://www.gnu.org/software/parallel/ installé, vous pouvez le faire:
Vous pouvez installer GNU Parallel simplement en:
Regardez les vidéos d'introduction pour GNU Parallel pour en savoir plus: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
la source
Pour répondre à vos deux questions:
wait
commande, vous pouvez demander au shell d'attendre la fin de tous les processus en arrière-plan avant de poursuivre.Voici le script modifié afin qu'il
j
soit utilisé pour garder une trace du nombre de processus d'arrière-plan. Une foisNB_CONCURRENT_PROCESSES
atteint, le script sera réinitialiséj
à 0 et attendra la fin de tous les processus d'arrière-plan avant de reprendre son exécution.la source
$f
etc. (3) Utilisation[
pour les scripts compatibles POSIX, mais pour le bash pur[[
est toujours préféré. Dans ce cas,((
est plus approprié pour l'arithmétique.