J'ai un problème de script shell où je reçois un répertoire plein de fichiers d'entrée (chaque fichier contenant de nombreuses lignes d'entrée), et je dois les traiter individuellement, en redirigeant chacune de leurs sorties vers un fichier unique (aka, file_1.input needs à capturer dans file_1.output, etc.).
Pré-parallèle , je voudrais simplement parcourir chaque fichier du répertoire et exécuter ma commande, tout en faisant une sorte de minuterie / technique de comptage pour ne pas submerger les processeurs (en supposant que chaque processus a un temps d'exécution constant). Cependant, je sais que ce ne sera pas toujours le cas, donc l'utilisation d'une solution de type "parallèle" semble être le meilleur moyen d'obtenir le multi-threading du script shell sans écrire de code personnalisé.
Bien que j'aie pensé à quelques façons de fouetter en parallèle pour traiter chacun de ces fichiers (et me permettre de gérer mes cœurs efficacement), ils semblent tous hacky. J'ai ce que je pense être un cas d'utilisation assez facile, je préférerais donc le garder aussi propre que possible (et rien dans les exemples parallèles ne semble ressortir comme étant mon problème.
Toute aide serait appréciée!
exemple de répertoire d'entrée:
> ls -l input_files/
total 13355
location1.txt
location2.txt
location3.txt
location4.txt
location5.txt
Scénario:
> cat proces_script.sh
#!/bin/sh
customScript -c 33 -I -file [inputFile] -a -v 55 > [outputFile]
Mise à jour : Après avoir lu la réponse d'Ole ci-dessous, j'ai pu rassembler les pièces manquantes pour ma propre implémentation parallèle. Bien que sa réponse soit excellente, voici mes recherches supplémentaires et les notes que j'ai prises:
Au lieu d'exécuter mon processus complet, j'ai pensé commencer par une commande de preuve de concept pour prouver sa solution dans mon environnement. Voir mes deux implémentations différentes (et notes):
find /home/me/input_files -type f -name *.txt | parallel cat /home/me/input_files/{} '>' /home/me/output_files/{.}.out
Utilise find (pas ls, qui peut entraîner des problèmes) pour rechercher tous les fichiers applicables dans mon répertoire de fichiers d'entrée, puis redirige leur contenu vers un répertoire et un fichier séparés. Mon problème d'en haut était la lecture et la redirection (le script réel était simple), donc remplacer le script par cat était une bonne preuve de concept.
parallel cat '>' /home/me/output_files/{.}.out ::: /home/me/input_files/*
Cette deuxième solution utilise le paradigme de variable d'entrée parallèle pour lire les fichiers, mais pour un novice, c'était beaucoup plus déroutant. Pour moi, l'utilisation de find a and pipe a très bien répondu à mes besoins.
la source
La méthode standard consiste à configurer une file d'attente et à générer un nombre illimité de travailleurs qui savent comment extraire quelque chose de la file d'attente et le traiter. Vous pouvez utiliser un fifo (alias nommé pipe) pour la communication entre ces processus.
Voici un exemple naïf pour démontrer le concept.
Un script de file d'attente simple:
Et un travailleur:
process_file
pourrait être défini quelque part dans votre travailleur, et il peut faire tout ce que vous en avez besoin.Une fois que vous disposez de ces deux éléments, vous pouvez disposer d'un simple moniteur qui démarre le processus de file d'attente et n'importe quel nombre de processus de travail.
Script de moniteur:
Voilà. Si vous faites cela, il est préférable de configurer le fifo sur le moniteur et de transmettre le chemin d'accès à la file d'attente et aux travailleurs, afin qu'ils ne soient pas couplés et ne soient pas collés à un emplacement spécifique pour le fifo. Je l'ai configuré de cette façon dans la réponse spécifiquement, il est donc clair que ce que vous utilisez lorsque vous le lisez.
la source
monitor_workers
c'est commeprocess_file
- c'est une fonction qui fait ce que vous voulez. À propos du moniteur - vous aviez raison; il devrait sauver les pids de ses ouvriers (afin qu'il puisse envoyer un signal d'arrêt) et le compteur doit être incrémenté lorsqu'il démarre un ouvrier. J'ai édité la réponse pour l'inclure.parallel
. Je pense que c'est votre idée, pleinement mise en œuvre.Un autre exemple:
J'ai trouvé les autres exemples inutilement complexes, alors que dans la plupart des cas, c'est ce que vous cherchiez peut-être.
la source
Un outil couramment disponible qui peut faire la parallélisation est make. GNU make et quelques autres ont un
-j
possibilité d'effectuer des builds parallèles.Exécutez
make
comme ceci (je suppose que les noms de vos fichiers ne contiennent pas de caractères spéciaux, cemake
n'est pas bon avec ceux-ci):la source
C'est pour exécuter la même commande sur un grand ensemble de fichiers dans le répertoire courant:
Cela exécute le
customScript
sur chaquetxt
fichier, en mettant la sortie dans desouttxt
fichiers. Changez selon vos besoins. La clé pour que cela fonctionne est le traitement du signal, en utilisant SIGUSR1 afin que le processus enfant puisse faire savoir au processus parent que c'est fait. L'utilisation de SIGCHLD ne fonctionnera pas car la plupart des instructions du script généreront des signaux SIGCHLD vers le script shell. J'ai essayé ceci en remplaçant votre commande parsleep 1
, le programme a utilisé 0,28s de CPU utilisateur et 0,14s de CPU système; ce n'était que sur environ 400 fichiers.la source
wait
qui est suffisamment «intelligent»; mais il reviendra après avoir reçu leSIGUSR1
signal. L'enfant / travailleur envoie unSIGUSR1
au parent, qui est pris (trap
), et décrémente$worker
(trap
clause) et revient anormalement dewait
, permettant à laif [ $worker -lt $num_workers ]
clause de s'exécuter.Ou utilisez simplement
xargs -P
, pas besoin d'installer de logiciel supplémentaire:Un peu d'explication pour les options:
-I'XXX'
définit la chaîne qui sera remplacée dans le modèle de commande par le nom de fichier-P4
exécutera 4 processus en parallèle-n1
ne mettra qu'un seul fichier par exécution même si deux XXX sont trouvés-print0
et-0
travailler ensemble, vous permettant d'avoir des caractères spéciaux (comme des espaces) dans les noms de fichiersla source