J'ai une tâche qui traite une liste de fichiers sur stdin. Le temps de démarrage du programme est important et le temps nécessaire à chaque fichier varie considérablement. Je veux générer un nombre important de ces processus, puis envoyer le travail à ceux qui ne sont pas occupés. Il existe plusieurs outils de ligne de commande différents qui font presque ce que je veux, je l'ai réduit à deux options presque opérationnelles:
find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob
Le problème est que cela split
fait un round-robin pur, donc l'un des processus prend du retard et reste en arrière, retardant la fin de l'opération entière; tandis que parallel
veut générer un processus par N lignes ou octets d'entrée et je finis par passer trop de temps sur les frais généraux de démarrage.
Y a-t-il quelque chose comme ça qui réutilisera les processus et les lignes d'alimentation vers les processus qui ont débloqué les stdins?
la source
split
commande? Le nom est en conflit avec l' utilitaire de traitement de texte standard .myjob
est prête à recevoir plus de commentaires. Il n'y a aucun moyen de savoir qu'un programme est prêt à traiter plus d'entrée, tout ce que vous pouvez savoir, c'est qu'un tampon quelque part (un tampon de canal, un tampon stdio) est prêt à recevoir plus d'entrée. Pouvez-vous arranger votre programme pour envoyer une sorte de demande (par exemple afficher une invite) quand il est prêt?read
appels ferait l'affaire. C'est un effort de programmation assez important.-l 1
dans lesparallel
arguments? IIRC, qui indique en parallèle de traiter une ligne d'entrée par tâche (c'est-à-dire un nom de fichier par fork de myjob, donc beaucoup de frais généraux de démarrage).Réponses:
Cela ne semble pas possible dans un cas aussi général. Cela implique que vous avez un tampon pour chaque processus et vous pouvez regarder les tampons de l'extérieur pour décider où placer la prochaine entrée (planification) ... Bien sûr, vous pourriez écrire quelque chose (ou utiliser un système de traitement par lots comme slurm)
Mais en fonction du processus, vous pourrez peut-être prétraiter l'entrée. Par exemple, si vous souhaitez télécharger des fichiers, mettre à jour des entrées à partir d'une base de données ou similaire, mais 50% d'entre eux finiront par être ignorés (et donc vous avez une grande différence de traitement en fonction de l'entrée), alors, il suffit de configurer un pré-processeur qui vérifie quelles entrées vont prendre du temps (le fichier existe, les données ont été modifiées, etc.), donc tout ce qui vient de l'autre côté est garanti pour prendre un temps assez égal. Même si l'heuristique n'est pas parfaite, vous pourriez vous retrouver avec une amélioration considérable. Vous pouvez vider les autres dans un fichier et les traiter ensuite de la même manière.
Mais cela dépend de votre cas d'utilisation.
la source
Non, il n'y a pas de solution générique. Votre répartiteur doit savoir quand chaque programme est prêt à lire une autre ligne, et il n'y a pas de norme à ma connaissance qui le permette. Tout ce que vous pouvez faire est de mettre une ligne sur STDOUT et d'attendre que quelque chose le consomme; il n'y a pas vraiment de bon moyen pour le producteur sur un pipeline de dire si le prochain consommateur est prêt ou non.
la source
Je ne pense pas. Dans mon magazine préféré, il y avait une fois un article sur la programmation bash qui faisait ce que vous vouliez. Je suis prêt à croire que s'il y avait eu des outils pour le faire, ils les auraient mentionnés. Vous voulez donc quelque chose dans le sens de:
De toute évidence, vous pouvez modifier l'invocation du script de travail réel à votre guise. Le magazine que je mentionne au départ fait des choses comme mettre en place des tuyaux et démarrer réellement les threads de travail. Vérifiez
mkfifo
cela, mais cet itinéraire est beaucoup plus compliqué car les processus de travail doivent signaler au processus maître qu'ils sont prêts à recevoir plus de données. Vous avez donc besoin d'un fifo pour chaque processus de travail pour lui envoyer des données et d'un fifo pour que le processus maître reçoive des informations des travailleurs.AVERTISSEMENT J'ai écrit ce script du haut de ma tête. Il peut avoir des problèmes de syntaxe.
la source
find . -type f | while read i
plutôt quefor i in $(find . -type f)
.Pour GNU Parallel, vous pouvez définir la taille du bloc à l'aide de --block. Cependant, cela nécessite que vous ayez suffisamment de mémoire pour conserver 1 bloc en mémoire pour chacun des processus en cours d'exécution.
Je comprends que ce n'est pas précisément ce que vous recherchez, mais cela peut être une solution acceptable pour l'instant.
Si vos tâches prennent en moyenne le même temps, vous pourrez peut-être utiliser mbuffer:
la source
Essaye ça:
mkfifo
pour chaque processus.Accrochez-vous ensuite
tail -f | myjob
à chaque fifo.Par exemple, configurer les travailleurs (processus myjob)
En fonction de votre application (myjob), vous pouvez peut-être utiliser des jobs -s pour rechercher des jobs arrêtés. Sinon, répertoriez les processus triés par CPU et sélectionnez celui qui consomme le moins de ressources. D'avoir le rapport de travail lui-même, par exemple en définissant un indicateur dans le système de fichiers quand il veut plus de travail.
En supposant que le travail s'arrête en attendant l'entrée, utilisez
jobs -sl
pour découvrir le pid d'un travail arrêté et lui attribuer un travail, par exempleJ'ai testé cela avec
Je dois admettre que cela vient d'être concocté donc ymmv.
la source
Ce qui est vraiment nécessaire pour résoudre ce problème est un mécanisme de file d'attente d'un certain type.
Est-il possible que les travaux lisent leur entrée à partir d'une file d'attente, telle qu'une file d'attente de messages SYSV, puis que les programmes exécutés en parallèle poussent simplement les valeurs dans la file d'attente?
Une autre possibilité consiste à utiliser un répertoire pour la file d'attente, comme ceci:
pending
mv
des premier fichier qu'il voit dans le répertoire vers un répertoire frère depending
, nomméinprogress
.pending
la source
exposant la réponse de @ ash, vous pouvez utiliser une file d'attente de messages SYSV pour distribuer le travail. Si vous ne voulez pas écrire votre propre programme en C, un utilitaire appelé
ipcmd
peut vous aider. Voici ce que j'ai mis en place pour passer la sortie defind $DIRECTORY -type f
à un$PARALLEL
certain nombre de processus:Voici un essai:
la source
À moins que vous puissiez estimer la durée de traitement d'un fichier d'entrée particulier et que les processus de travail n'ont aucun moyen de faire rapport au planificateur (comme ils le font dans les scénarios de calcul parallèle normaux - souvent via MPI ), vous n'avez généralement pas de chance - soit payer la pénalité de certains travailleurs qui traitent les données d'entrée plus longtemps que d'autres (en raison de l'inégalité des données d'entrée), soit payer la peine de générer un nouveau processus unique pour chaque fichier d'entrée.
la source
GNU Parallel a changé au cours des 7 dernières années. Aujourd'hui, il peut le faire:
Cet exemple montre que plus de blocs sont donnés aux processus 11 et 10 qu'aux processus 4 et 5 car 4 et 5 lisent plus lentement:
la source