Je veux traiter de nombreux fichiers et comme j'ai ici un tas de cœurs, je veux le faire en parallèle:
for i in *.myfiles; do do_something $i `derived_params $i` other_params; done
Je connais une solution Makefile mais mes commandes ont besoin des arguments de la liste de globbing du shell. Ce que j'ai trouvé c'est:
> function pwait() {
> while [ $(jobs -p | wc -l) -ge $1 ]; do
> sleep 1
> done
> }
>
Pour l'utiliser, il suffit de mettre & après les jobs et un appel pwait, le paramètre donne le nombre de processus parallèles:
> for i in *; do
> do_something $i &
> pwait 10
> done
Mais cela ne fonctionne pas très bien, par exemple, je l'ai essayé avec par exemple une boucle for pour convertir de nombreux fichiers mais en me donnant des erreurs et des travaux non effectués.
Je ne peux pas croire que cela ne soit pas encore fait car la discussion sur la liste de diffusion zsh est si ancienne maintenant. Alors tu sais mieux?
echo "DONE"
après la boucle qui a été exécutée avant que les travaux actifs ne soient terminés. => Cela m'a fait penser que le travail n'était pas fait.Réponses:
Un makefile est une bonne solution à votre problème. Vous pouvez programmer cette exécution parallèle dans un shell, mais c'est difficile, comme vous l'avez remarqué. Une implémentation parallèle de make se chargera non seulement de démarrer des travaux et de détecter leur terminaison, mais également de gérer l'équilibrage de charge, ce qui est délicat.
L'exigence de globbing n'est pas un obstacle: il existe des implémentations de make qui le supportent. GNU make, qui a une extension générique telle que
$(wildcard *.c)
et un accès shell tel que$(shell mycommand)
(recherchez les fonctions dans le manuel GNU make pour plus d'informations). C'est la valeur par défautmake
sous Linux et disponible sur la plupart des autres systèmes. Voici un squelette Makefile que vous pourrez peut-être adapter à vos besoins:Exécutez quelque chose comme
make -j4
pour exécuter quatre tâches en parallèle oumake -j -l3
pour maintenir la charge moyenne autour de 3.la source
Je ne sais pas à quoi ressemblent vos arguments dérivés. Mais avec GNU Parallel http: // www.gnu.org/software/parallel/ vous pouvez le faire pour exécuter un travail par cœur de processeur:
Si vous voulez simplement dériver le .extension, le {.} Peut être pratique:
Regardez la vidéo d'introduction à GNU Parallel sur http://www.youtube.com/watch?v=OpaiGYxkSuQ
la source
Est-ce que l'utilisation de la
wait
commande du shell ne fonctionnerait pas pour vous?Votre boucle exécute un travail puis l'attend, puis effectue le travail suivant. Si ce qui précède ne fonctionne pas pour vous, alors le vôtre pourrait mieux fonctionner si vous déménagez
pwait
aprèsdone
.la source
for
boucles imbriquées pour limiter cela:for file in *; do for i in {1..10}; do do_something "$i" & done; wait; done
(non testé) Cela devrait faire dix à la fois et attendre que les dix de chaque groupe soient terminés avant de commencer les dix suivants. Votre boucle fait un à la fois ce qui est&
discutable. Voir la question à laquelle JRobert a lié pour d'autres options. Recherchez sur Stack Overflow d'autres questions similaires aux vôtres (et celle-là).for i in *
. Il devrait passer des arguments à la boucle avec un tuyau ou quelque chose. Ensuite, au lieu d'une boucle interne, vous pouvez exécuter un compteur d'incrémentation et exécuter"micro-"wait"-s"
chaque "$ ((i% 32))" -eq '0'wait
avec une contre-boucle intérieure a bien fonctionné pour moi. Merci!Pourquoi personne n'a-t-il encore mentionné xargs?
En supposant que vous ayez exactement trois arguments,
Sinon, utilisez un délimiteur (null est pratique pour cela):
EDIT: pour ce qui précède, chaque paramètre doit être séparé par un caractère nul, puis le nombre de paramètres doit être spécifié avec xargs -n.
la source
J'ai essayé certaines des réponses. Ils rendent le script un peu plus complexe que nécessaire. Idéalement, l'utilisation de
parallel
ouxargs
serait préférable, mais si les opérations à l'intérieur de la boucle for sont compliquées, il pourrait être problématique de créer un fichier de grandes et longues lignes à fournir en parallèle. au lieu de cela, nous pourrions utiliser la source comme suitAinsi, pour votre problème, la solution ressemblerait à
définir faire quelque chose comme
do_something.sh
}
exécuter avec
xarg
ougnu parallel
Je suppose que l'indépendance fonctionnelle des itérations de for est implicite.
la source