Quatre tâches en parallèle … comment est-ce que je fais ça?

J'ai un tas d'images PNG sur un directory. J'ai une application appelée pngout que je cours 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 file à la fois prend beaucoup de time. Après avoir exécuté cette application, je vois que le CPU est à seulement 10%. J'ai donc découvert que je peux split ces files en 4 lots, mettre chaque lot dans un directory et tirer 4, de quatre windows de terminal, quatre process, donc j'ai quatre instances de mon script, en même time, le travail prend 1/4 du time.

Le deuxième problème est que j'ai perdu du time à split les images et les lots et à copyr le script dans quatre directorys, ouvrir 4 windows de terminal, bla bla …

Comment cela avec un script, sans avoir à split quoi que ce soit?

Je veux dire deux choses: d'abord comment puis-je partir d'un script bash, tirer un process à l'arrière-plan? (juste append & à la fin?) Deuxièmement: comment puis-je arrêter d'envoyer des tâches à l'arrière-plan après l'envoi des quasortingèmes tâches et mettre le script pour attendre la fin des tâches? Je veux dire, simplement envoyer une nouvelle tâche à l'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 va triggersr des zillions de tâches en arrière-plan et le processeur va se boucher.

    Si vous avez une copy de xargs qui supporte l'exécution parallèle avec -P , vous pouvez simplement faire

     printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{} 

    Pour d'autres idées, le wiki Wooledge Bash a une section dans l'article de gestion des process décrivant exactement ce que vous voulez.

    En plus des solutions déjà proposées, vous pouvez créer un makefile qui décrit comment rendre un file compressé non compressé et utiliser make -j 4 pour exécuter 4 tâches en parallèle. Le problème est que vous devrez nommer les files compressés et non compressés différemment ou les stocker dans des directorys différents, sinon écrire une règle make raisonnable sera impossible.

    Si vous avez GNU Parallel http://www.gnu.org/software/parallel/ installed vous pouvez le faire:

     parallel ./pngout -s0 {} R{} ::: *.png 

    Vous pouvez installer GNU Parallel simplement en:

     wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel chmod 755 parallel cp parallel sem 

    Regardez les videos d'intro pour GNU Parallel pour en savoir plus: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

    Pour répondre à vos deux questions:

    • oui, l'ajout & à la fin de la ligne vous requestra shell pour lancer un process d'arrière-plan.
    • à l'aide de la command wait , vous pouvez requestr au shell d'attendre la fin de tous les process en arrière-plan avant de continuer.

    Voici le script modifié afin que j soit utilisé pour garder une trace du nombre de process d'arrière-plan. Lorsque NB_CONCURRENT_PROCESSES est atteint, le script réinitialise j à 0 et attend que tous les process d'arrière-plan soient terminés avant de reprendre l'exécution.

     files=(./*.png) nb_concurrent_processes=4 j=0 for f in "${files[@]}" do echo "Processing $f file..." # take action on each file. $f store current file name ./pngout -s0 "$f" R"${f/\.\//}" & ((++j == nb_concurrent_processes)) && { j=0; wait; } done