Minimal & # 8220; File d'attente des tâches & # 8221; avec des outils Linux standard pour exploiter le processeur multicœur

StackOverflow https://stackoverflow.com/questions/832253

  •  06-07-2019
  •  | 
  •  

Question

Quel est le moyen le plus simple et le plus simple de créer un système de file d'attente de tâches minimal pour Linux à l'aide d'outils bash et communs?

J'ai un fichier avec 9'000 lignes, chaque ligne a une ligne de commande bash, les commandes sont complètement indépendantes.

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log
...

Ma boîte a plus d'un cœur et je veux exécuter X tâches en même temps. J'ai cherché sur le Web un bon moyen de le faire. Apparemment, beaucoup de gens ont ce problème, mais personne n’a pour l’instant une bonne solution.

Il serait intéressant que la solution présente les fonctionnalités suivantes:

  • peut interpréter plusieurs commandes (par exemple, commande; commande )
  • peut interpréter les redirections de flux sur les lignes (par exemple, ls > /tmp/ls.txt)
  • utilise uniquement les outils Linux courants

Bonus si cela fonctionne sur d'autres clones Unix sans exigences trop exotiques.

Était-ce utile?

La solution

Pouvez-vous convertir votre liste de commandes en un Makefile? Si tel est le cas, vous pouvez simplement exécuter "make -j X".

Autres conseils

Parallèle GNU http://www.gnu.org/software/parallel/ est un outil plus général pour la parallélisation que PPSS.

Si le fichier d'exécution contient:

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log

vous pouvez faire:

cat runfile | parallel -j+0

qui exécutera une commande par cœur de processeur.

Si vos commandes sont aussi simples que ci-dessus, vous n'avez même pas besoin de runfile mais pouvez le faire:

seq 1 3 | parallel -j+0 'command {} > Logs/{}.log'

Si vous avez plus d’ordinateurs disponibles pour effectuer le traitement, consultez les options --sshlogin et --trc pour GNU parallèle.

D'accord, après avoir posé la question ici, j'ai trouvé le projet suivant qui semble prometteur: ppss .

Modifier: Ce n'est pas ce que je veux, PPSS se concentre sur le traitement de "tous les fichiers du répertoire A".

Eh bien, c’est quand même une question amusante.

Voici ce que je ferais, en supposant bash (1) bien sûr.

  • déterminez combien de ces commandes peuvent utilement être exécutées simultanément. Ce ne sera pas juste le nombre de cœurs; beaucoup de commandes seront suspendues pour les E / S et ce genre de chose. Appelez ce numéro N. N = 15 par exemple.
  • configurez un gestionnaire de signal d'interruption pour le signal SIGCHLD, qui se produit lorsqu'un processus enfant se termine. trap signalHandler SIGCHLD
  • cat votre liste de commandes dans un tuyau
  • écrit une boucle qui lit stdin et exécute les commandes une par une en décrémentant un compteur. Lorsque le compteur est à 0, il attend s.
  • votre gestionnaire de signal, qui tourne sur SIGCHLD, incrémente ce compteur.

Alors maintenant, il lance les premières commandes N , puis attend. Lorsque le premier enfant se termine, l'attente est renvoyée, il lit une autre ligne, exécute une nouvelle commande et attend à nouveau.

Maintenant, il s’agit d’un cas qui prend en charge de nombreux travaux se terminant de manière rapprochée. Je soupçonne que vous pouvez vous en tirer avec une version plus simple:

 N=15
 COUNT=N
 cat mycommands.sh | 
 while read cmd 
 do
   eval $cmd &
   if $((count-- == 0))
   then
       wait
   fi
 od

Maintenant, celui-ci lancera les 15 premières commandes, puis exécutera les autres commandes une par une à la fin d'une commande.

Le script Mapreduce Bash est un plaisir similaire à l’informatique distribuée:

http://blog.last.fm/2009/04 / 06 / mapreduce-bash-script

Et merci d’avoir signalé les PPS!

Vous pouvez utiliser la commande xargs . Son - max-procs fait ce que vous voulez. Par exemple, la solution de Charlie Martin devient avec xargs:

tr '\012' '\000' <mycommands.sh |xargs --null --max-procs=$X bash -c

détails:

  • X est le nombre de processus max. E.g: X = 15. --max-procs fait la magie
  • le premier tr est ici pour terminer les lignes par des octets nuls pour l'option xargs --null afin que la redirection des guillemets, etc. ne soient pas développés à tort
  • bash -c exécute la commande

Je l'ai testé avec ce fichier mycommands.sh, par exemple:

date
date "+%Y-%m-%d" >"The Date".txt
wc -c <'The Date'.txt >'The Count'.txt

Il s'agit d'un cas spécifique, mais si vous essayez de traiter un ensemble de fichiers et de générer un autre ensemble de fichiers de sortie, vous pouvez démarrer #cores le nombre de processus et vérifier s'il existe un fichier de sortie avant de le traiter. L'exemple ci-dessous convertit un répertoire de fichiers .m4b en fichiers .mp3:

Exécutez cette commande autant de fois que vous avez de cœurs:

ls * m4b | pendant la lecture f; faire le test -f $ {f% m4b} mp3 || mencoder-of rawaudio " $ f " -oac mp3lame -ovc copie -o $ {f% m4b} mp3; terminé &

Vous pouviez voir ma file de tâches écrite sur bash: https://github.com/pavelpat/yastq

Queue de tâche + Ajout en parallèle + dynamique

Utilisant une FIFO, ce script se lance lui-même pour traiter la file d'attente. De cette façon, vous pouvez ajouter des commandes à la file d'attente à la volée (lorsque la file d'attente est déjà lancée).

Utilisation: ./queue Commande [nbre d'enfants] [nom de la file d'attente]

Exemple, avec 1 thread:

./queue "sleep 5; echo ONE"
./queue "echo TWO"

Sortie:

ONE
TWO

Exemple, avec 2 threads:

./queue "sleep 5; echo ONE" 2
./queue "echo TWO"

Sortie:

TWO
ONE

Exemple, avec 2 files d'attente:

./queue "sleep 5; echo ONE queue1" 1 queue1
./queue "sleep 3; echo ONE queue2" 1 queue2

Sortie:

ONE queue2
ONE queue1

Le script (enregistrez-le sous forme de "file d'attente" et de file d'attente chmod + x):

    #!/bin/bash

    #Print usage
    [[ $# -eq 0 ]] && echo Usage: <*> Command [# of children] [Queue name] && exit

    #Param 1 - Command to execute
    COMMAND="$1"

    #Param 2 - Number of childs in parallel
    MAXCHILD=1
    [[ $# -gt 1 ]] && MAXCHILD="$2"

    #Param 3 - File to be used as FIFO
    FIFO="/tmp/defaultqueue"
    [[ $# -gt 2 ]] && FIFO="$3"

    #Number of seconds to keep the runner active when unused
    TIMEOUT=5

    runner(){
      #Associate file descriptor 3 to the FIFO
      exec 3"$FIFO"

      while read -u 3 -t $TIMEOUT line; do
        #max child check
        while [ `jobs | grep Running | wc -l` -ge "$MAXCHILD" ]; do
          sleep 1
        done

        #exec in backgroud
        (eval "$line")&
      done
      rm $FIFO
    }

    writer(){
      #fork if the runner is not running
      lsof $FIFO >/dev/null || (<*> "QueueRunner" "$MAXCHILD" "$FIFO" &)

      #send the command to the runner
      echo "$COMMAND" > $FIFO
    }

    #Create the FIFO file
    [[ -e "$FIFO" ]] || mkfifo "$FIFO"

    #Start the runner if in the runner fork, else put the command in the queue
    [[ "$COMMAND" == "QueueRunner" ]] && runner || writer

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top