101 votes

Paralléliser le script Bash

Disons que j'ai une boucle en bash:

for foo in `some-command`
do
   do-something $foo
done

do-something est en cpu, et j'ai un beau brillant à 4 cœurs du processeur. J'aimerais être capable d'exécuter jusqu'à 4 do-something'à la fois.

L'approche naïve semble être:

for foo in `some-command`
do
   do-something $foo &
done

Cela permettra d'exécuter tous do-somethings à la fois, mais il y a quelques inconvénients, surtout que quelque chose peut aussi avoir une importante I/O duquel l'exécution de tous à la fois pourrait ralentir un peu. L'autre problème, c'est que ce bloc de code renvoie immédiatement, donc pas moyen de faire d'autres travaux lorsque tous les do-somethings sont finis.

Comment écririez-vous de cette boucle, il y a donc de X do-somethings running à la fois?

71voto

fgm Points 5930

En fonction de ce que vous voulez faire, xargs peut également aider (ici: convertir des documents avec pdf2ps):

 cpus=$( ls -d /sys/devices/system/cpu/cpu[[:digit:]]* | wc -w )

find . -name \*.pdf | xargs --max-args=1 --max-procs=$cpus  pdf2ps
 

De la docs:

--max-procs = max-procs -P max-procs Exécution simultanée de processus max-procs; La valeur par défaut est 1. Si max-procs est égal à 0, xargs exécutera autant de processus que possible à la fois. Utilisez l'option -n avec -P; sinon, il y a de fortes chances qu'un seul exec soit fait.

41voto

Ole Tange Points 4907

Avec GNU Parallèle http://www.gnu.org/software/parallel/ vous pouvez écrire:

some-command | parallel do-something

GNU Parallèle prend également en charge l'exécution de travaux sur des ordinateurs distants. Ce sera exécuté par un PROCESSEUR de base sur les ordinateurs distants, même si elles peuvent avoir un nombre différent de noyaux:

some-command | parallel -S server1,server2 do-something

Un exemple plus complexe: Ici nous avons la liste des fichiers que nous voulons my_script pour exécuter sur. Les fichiers ont l'extension (peut-être .jpeg). Nous voulons que la sortie de my_script être mis en regard des fichiers dans basename.(p. ex. foo.jpeg -> foo.out). Nous voulons exécuter my_script une fois pour chaque cœur de l'ordinateur a et nous voulons exécuter sur l'ordinateur local, trop. Pour les ordinateurs à distance nous voulons que le dossier soit traité transférées à l'ordinateur. Lorsque my_script finitions, nous voulons foo.hors transférés ensuite, nous voulons foo.jpeg et toto.hors supprimé de l'ordinateur distant:

cat list_of_files | \
parallel --trc {.}.out -S server1,server2,: \
"my_script {} > {.}.out"

GNU Parallèle permet de s'assurer de la sortie de chaque tâche n'est pas de mélanger, de sorte que vous pouvez utiliser la sortie comme entrée pour un autre programme:

some-command | parallel do-something | postprocess

Voir les vidéos pour plus d'exemples: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

22voto

bstark Points 330
maxjobs = 4
paralléliser () {
        tandis que [$ # -gt 0]; faire
                jobcnt = (`jobs -p`)
                if [$ {# jobcnt [@]} -lt $ maxjobs]; puis
                        faire quelque chose 1 $ &
                        décalage  
                Fi
        terminé
        attendre
}

paralléliser arg1 arg2 "5 arguments au troisième emploi" arg4 ...

11voto

skolima Points 12221

Au lieu d'une plaine bash, utiliser un Makefile, puis spécifiez le nombre de simultanée des emplois avec make -jX , où X est le nombre de travaux à exécuter à la fois.

Ou vous pouvez utiliser wait ("man wait"): lancer plusieurs processus enfants, appelez - wait - il de sortie lorsque l'enfant des processus de finition.

maxjobs = 10

foreach line in `cat file.txt` {
 jobsrunning = 0
 while jobsrunning < maxjobs {
  do job &
  jobsrunning += 1
 }
wait
}

job ( ){
...
}

Si vous avez besoin de stocker l'emploi du résultat, puis d'affecter le résultat à une variable. Après l' wait que vous venez de vérifier que la variable contient.

8voto

tessein Points 1705

Peut-être essayer un utilitaire de parallélisation au lieu de réécrire la boucle? Je suis un grand fan de xjobs. J'utilise tout le temps xjobs pour copier en masse des fichiers sur notre réseau, généralement lors de la configuration d'un nouveau serveur de base de données. http://www.maier-komor.de/xjobs.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X