Journal executions de commandes shell en parallele: par

Posté par (page perso) .
Tags : aucun
10
29
nov.
2009
Salut,

Je lance un nouveau petit projet open source:
---
Executes commands from a batch file or from a pipe in parallel.
On a multi-core machine, the number of cores is the default
parallelization factor.
---

Pour ceux que ca interesse, ca se passe par ici:

https://savannah.nongnu.org/projects/par/

Pour l'instant, c'est constitue essentiellement d'un script python tout
simple.
Je l'ai deja utilise au boulot pour des batch de 1000 jobs, sur des machines
avec 4 ou 16 coeurs, ca marche plutot bien. ;0)

J'espere que ca pourra etre utile a d'autres gens.

A+,
Francois.
  • # Exemple d'utilisation

    Posté par (page perso) . Évalué à 9.

    Comment s'utilise ton programme ?

    Car si l'on utilise des tubes avec |, les commandes sont déjà exécutées en parallèle. On peut aussi les exécuter en parallèle avec &, donc ton programme doit faire quelque chose de vraiment mieux, mais je n'ai pas trouvé, même en allant dans le dépôt git.

    Envoyé depuis mon lapin.

    • [^] # Re: Exemple d'utilisation

      Posté par . Évalué à -2.

      En parallèle ? Au contraire, elles sont exécutées l'une après l'autre vu qu'il faut la sortie de la première commande pour pouvoir entammer le traitement de la 2e (et ainsi de suite).

      J'ai d'ailleurs du mal à voir comment on pourrait paralléliser tout ça !
      • [^] # Re: Exemple d'utilisation

        Posté par (page perso) . Évalué à 9.

        Non, elles sont lancées toutes en même temps (ou presque), et celles en sorties des tubes attendent les informations en entrée.

        Si une commande retourne plusieurs informations en sortie, elle peut continuer à travailler pendant que la deuxième traite le premier lot d'informations. Dans ce cas, c'est parallélisé.

        Envoyé depuis mon lapin.

      • [^] # Re: Exemple d'utilisation

        Posté par (page perso) . Évalué à 6.

        Non, elles sont bien exécutés en parallèle.
        La deuxièmes est juste "en attente" de données de la première tant que la première n'a pas écrit sur sa sortie. Mais après cela, l'exécution se fait en parallèle : la première continue de générer sa sortie pendant que la deuxièmes reçoit le contenu, le traite, et se remet en attente si nécessaire.
        Et heureusement, car les données dans le pipe pourraient être énorme s'il fallait attendre que la première est fini son boulot pour exécuter la seconde
      • [^] # Re: Exemple d'utilisation

        Posté par . Évalué à 6.

        C'est parallèle sous Linux, mais peut être pas sous l'autre OS (ou alors ça dépend des versions), mais de toute façon, le grep sur /proc fait que ton programme ne marchera que sous Linux ;)

        Par contre, les pipes classiques ont un buffer limité (64 k je crois, ou 256k, en tout cas pas bien gros), alors que dans ton programme, pour le buffer entre les sorties des commandes et la sortie de ton programme, je ne vois aucune limite. En fonction de ce que l'on veut, ça peut être bien ou pas.

        • [^] # Re: Exemple d'utilisation

          Posté par . Évalué à 2.

          4Ko d'après mes tests.

          Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

          • [^] # Re: Exemple d'utilisation

            Posté par . Évalué à 2.

            En fait, la taille d'une page (ou un multiple).
            • [^] # Re: Exemple d'utilisation

              Posté par . Évalué à 3.

              la commande ulimit -p permet de connaître et de changer la taille des pipes.

              La taille est donnée en multiple de 512 octets et c'est 8 par défaut, d'où les pipes de 4ko.
    • [^] # Re: Exemple d'utilisation

      Posté par (page perso) . Évalué à 3.

      Un exemple:

      parallel.py -i commandes

      'commandes' doit contenir quelque chose comme:

      echo toto
      echo titi
      echo tata

      Bien sur, c'est un exemple bateau juste pour montrer que ca
      parrallelise bien l'execution.
      • [^] # Re: Exemple d'utilisation

        Posté par . Évalué à 6.

        Quel est la différence avec
        echo toto & echo titi & echo tata
        ?

        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: Exemple d'utilisation

          Posté par . Évalué à 3.

          Dans son journal : "On a multi-core machine, the number of cores is the default
          parallelization factor.", donc le nombre de process à la fois est limité. Contrairement à "&" qui en lance un nombre non-limité (plein par processeur au lieu d'un seul).
          • [^] # Re: Exemple d'utilisation

            Posté par (page perso) . Évalué à 1.

            C'est d'ailleurs bien dommage que bash ne propose pas ce genre de mécanisme par défaut. Il y a quand même quelques manières plus ou moins alambiquées de faire cela avec bash:

            http://stackoverflow.com/questions/1537956/bash-limit-the-nu(...)
            • [^] # Re: Exemple d'utilisation

              Posté par . Évalué à 2.

              "Bien dommage" ? Il y a une contrainte de compatibilité avec le shell POSIX quand même. Un shell ne peut pas se permettre toutes les libertés.
              • [^] # Re: Exemple d'utilisation

                Posté par (page perso) . Évalué à 1.

                Rien n'interdit d'ajouter des mécanismes. Est-ce que la norme POSIX interdit d'ajouter une variable d'environnement MAX_CONCURRENT_JOBS qui rend l'opérateur & bloquant quand on dépasse ce nombre? Je ne le pense pas.

                D'autre part, bash n'est déjà pas très posix compliant, il faut utiliser dash si on y tient vraiment. Mais la compatibilité Posix est-elle encore si importante dans le monde d'aujourd'hui?
                • [^] # Re: Exemple d'utilisation

                  Posté par . Évalué à 10.

                  "Est-ce que la norme POSIX interdit d'ajouter une variable d'environnement MAX_CONCURRENT_JOBS qui rend l'opérateur & bloquant quand on dépasse ce nombre? Je ne le pense pas."
                  Ca risque juste de bien péter des scripts.

                  "D'autre part, bash n'est déjà pas très posix compliant, il faut utiliser dash si on y tient vraiment."
                  Il y a une différence entre des features qui ajoutent des fonctions qui ne font pas de conflits avec la norme (par exemple le /dev/tcp de bash), et des fonctions qui entrent en conflit ("&" qui change complètement de comportement).

                  "Mais la compatibilité Posix est-elle encore si importante dans le monde d'aujourd'hui?"
                  A tous ceux qui écrivent des bashismes : OUI ! Tout le monde n'est pas encore soumis à GNU, il existe notamment d'autres OS que GNU, d'autres shells que bash...
                  • [^] # Re: Exemple d'utilisation

                    Posté par (page perso) . Évalué à -9.


                    Il y a une différence entre des features qui ajoutent des fonctions qui ne font pas de conflits avec la norme


                    Ben c'est le cas justement. On peut appeler la variable BASH_MAX_CONCURRENT_JOBS si tu préfères.

                    Tu es vraiment la définition d'un intégriste, les gens qui veulent jamais que rien change parce que "c'était mieux avant". Le posix c'est bien, mais seulement pour les trucs qui ont vocation d'être portés sur d'autres UNIX. 99.999% des scripts sont écrits pour un système, un OS et généralement un seul utilisateur.
                    • [^] # Re: Exemple d'utilisation

                      Posté par . Évalué à 6.

                      "Tu es vraiment la définition d'un intégriste, les gens qui veulent jamais que rien change parce que "c'était mieux avant"."
                      Gnagna, injure, attaque personnelle, ce que tu veux, m'en fous.

                      "Le posix c'est bien, mais seulement pour les trucs qui ont vocation d'être portés sur d'autres UNIX. 99.999% des scripts sont écrits pour un système, un OS et généralement un seul utilisateur."
                      Je crois que tu te méprends totalement sur l'utilisation des scripts.
                      • [^] # Re: Exemple d'utilisation

                        Posté par (page perso) . Évalué à -3.

                        Gnagna, injure, attaque personnelle, ce que tu veux, m'en fous.

                        Réponds au reste du post dans ce cas, spécifiquement la partie sur ma nouvelle proposition de nom de variable. D'un autre côté c'est vraiment dommage, cette absence totale de remise en question de soi.

                        Je crois que tu te méprends totalement sur l'utilisation des scripts.

                        Je te renvoie le compliment. Plus sérieusement, je pense qu'il est très difficile de généraliser, parce que nous avons tous une utilisation différente des ordinateurs. Pour le cas présent, je pense que la norme Posix est très importante pour certaines personnes (ceux qui écrivent des scripts qui ont vocation à être réutilisés), mais que cette norme ne doit pas freiner le reste d'entre nous. Tu le dis toi même, les deux peuvent bien cohabiter, si on fait attention à n'ajouter que des "des features qui ajoutent des fonctions qui ne font pas de conflits avec la norme ".
              • [^] # Re: Exemple d'utilisation

                Posté par . Évalué à 2.

                Je me pose des questions là dessus. La plupart des shells ont un mode de compatibilité en fonction du nom avec le quel on l'appel. En plus quand je vois un shell comme tcsh (et toute la famille de csh), je me demande bien où est la compatibilité avec POSIX là dedans.

                Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                • [^] # Re: Exemple d'utilisation

                  Posté par (page perso) . Évalué à 7.

                  csh et tcsh n'ont jamais proné la compatibilité avec sh (le seul truc qui est posix). Et oui, écrire des scripts avec csh, c'est
                  1/ mal parce http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/
                  2/ mal parce que niveau standard c'est bof

                  Quand à la portabilité, en général, il faut distinguer deux cas :
                  - les scripts d'admin pour soit, son parc, vous faites bien ce que vous voulez, si vous introduisez des choses un peu fantasques sur le parc, c'est vous qui aurez du boulot en plus

                  - les choses qui ont vocation à être redistribuée, alors là, les bashimes me font hurler. Oui tous les systèmes Unix n'ont pas un bash de base, et vivent très bien sans bash. Le standard c'est le bourne shell, ça demande pas un effort énorme d'écrire un script shell portable. C'est marrant comment les logiciels libres se targuent de respecter les standards, et ne sont pas foutu de respecter des choses comme Posix (je parle pas des autres gnuismes qu'on peut trouver dans du code C ou autre).
                  • [^] # Re: Exemple d'utilisation

                    Posté par (page perso) . Évalué à 0.

                    Quand à la portabilité, en général, il faut distinguer deux cas :

                    Tu oublies un troisième cas qui est beaucoup plus répandu qu'on ne le pense, à mon avis: les scripts écrits pour autre chose que de l'administration de réseau. Il n'y a pas que les admins réseau qui utilisent Unix, loin de là!
                  • [^] # Re: Exemple d'utilisation

                    Posté par (page perso) . Évalué à 1.

                    Et oui, écrire des scripts avec csh, c'est mal

                    Ben non, c'est pas "mal". Ca peut être mal adapaté dans un cas précis, mais pas "mal" ou "sale", etc. Restons sur du rationel, svp.
                  • [^] # Re: Exemple d'utilisation

                    Posté par . Évalué à 3.

                    J'ai pas encore vu l'avantage de bash ni de zsh pour les script par rapport à sh.

                    Sachant que dans bien des cas (même si je ne redistribue pas souvent mes scripts) je fais du perl.

                    Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

                  • [^] # Re: Exemple d'utilisation

                    Posté par . Évalué à 3.

                    C'est pas le moment de se poser la question de l'obsolescence de Posix, justement ? Déja Bash c'est plus de la toute première jeunesse ...
            • [^] # Re: Exemple d'utilisation

              Posté par . Évalué à 3.

              Oui, mais bon le resultat n'est pas le même


              echo toto
              echo titi
              echo tata

              est déterministe

              echo toto & echo titi & echo tata ne l'est pas. Le résultat peut être :

              toto
              titi
              tata

              ou bien

              tata
              titi
              toto


              [...]

              Quand a ajouter une limite à partir duquel "&" est bloquant c'est encore pire.
              On fait quoi pour les scripts qui lance une série de programmes qui ne rende jamais la main ...
              • [^] # Re: Exemple d'utilisation

                Posté par (page perso) . Évalué à -1.

                Quand a ajouter une limite à partir duquel "&" est bloquant c'est encore pire.
                On fait quoi pour les scripts qui lance une série de programmes qui ne rende jamais la main ...


                Ben, on enlève la limite? Je comprends vraiment pas cette vague d'opposition systématique à ma petite proposition...
            • [^] # Re: Exemple d'utilisation

              Posté par . Évalué à 4.

              Plus simple (et plus pourris) :


              #! /bin/sh

              LIMIT=4

              para()
              {
              while [ $(jobs | wc -l) -ge $LIMIT ]
              do
              sleep 1
              done
              echo "starting $1"
              $@ &
              return 0;
              }


              para sleep 10
              para sleep 100
              para sleep 1
              para sleep 10
              para sleep 1
              para sleep 10
              para sleep 1
              para sleep 10

              echo "end..."
              wait
      • [^] # Re: Exemple d'utilisation

        Posté par (page perso) . Évalué à 3.

        J'ai utiliser il y a des années le module perl Parallel::ForkManager

        apt-get install libparallel-forkmanager-perl

        En gros, il fait exactement ce que tu proposes, il suffit juste d'écrire un p'tit "wrapper" pour qu'il lance des commandes shell mais cela est très facile à faire.

        http://search.cpan.org/~dlux/Parallel-ForkManager-0.7.5/Fork(...)

        L'avantage de ce module est qu'il a très peu de dépendances. En gros, s'il y a perl sur la machine, une copie de ce module et cela marche.
  • # par

    Posté par . Évalué à 6.

    "par" est un nom déjà utilisé par le projet parchive. Plus exactement les commandes par et par2. Il n'y a pas vraiment confusion sur le but des projets, mais avoir le même nom pour les commandes peut être dommage.
    • [^] # Re: par

      Posté par . Évalué à 2.

      L'horreur..

      user@machine:~$par tab completion
      par par
      user@machine:~$

      THIS IS JUST A PLACEHOLDER. YOU SHOULD NEVER SEE THIS STRING.

      • [^] # Re: par

        Posté par (page perso) . Évalué à 5.

        Pour l'instant le script s'appelle parallel.py.
        Il n'y a pas de commande par donc.
  • # Petite astuce pour la programmation parallèle en python

    Posté par (page perso) . Évalué à 1.

    As-tu regardé du côté de multiprocessing.Pool? Je pense qu'il y a de quoi simplifier nettement l'implémentation de ton script.

    Plus de détails:

    http://stackoverflow.com/questions/1704401/is-there-a-simple(...)
  • # Been there, done that

    Posté par (page perso) . Évalué à 5.

    T'as plein d'applis comme ça dans le monde du grid computing qui font ce genre de choses depuis des années, et c'est pas forcément des logiciels propriétaires.
    Ça permet de distribuer sur les cores/processeurs d'une machine, de plusieurs machines, à travers des firewalls, d'avoir de la tolérances aux erreurs, etc…

    Regarde par exemple ça, c'est intéressant :
    http://web.yl.is.s.u-tokyo.ac.jp/~kaneda/vpg/
    http://www.logos.t.u-tokyo.ac.jp/gxp/
    (et si c'est pas 100% ce que tu fais, fais le tour des liens et publications citées par ces sites.)

    Sinon, un pipe, c'est séquentiel.
    Ça veut dire quoi "exécute les commandes d'un pipe en parallèle" ?
    • [^] # Re: Been there, done that

      Posté par (page perso) . Évalué à 6.

      Bon, je me répond car j'ai lu les autres commentaires, et je comprend ce que tu voulais dire par "exécuter les commandes d'un pipe en parallèle".

      Donc, en gros, si je fais

      A | B j'aurais idéalement A sur un cœur, et B sur un autre, c'est ça ?

      Bon, c'est cool ^^
      Mais tu fais ça statiquement, ou dynamiquement avec du vol de tâche si jamais t'as un proc qui se libère (car si tu lances en parallèle deux instances de programmes, chacun va faire son allocation sans se soucier de l'autre à moins que tu partages toutes tes tâches au niveau de la machine (ou au moins de l'utilisateur)).

      Ça commence simple avec des cas triviaux, mais ça a vite fait de devenir compliqué… (puis pas besoin de créer B tout de suite dans A|B si A met 20 minutes avant de faire la moindre sortie. Tu veux donc faire de la création paresseuse de processus s'il est en attente bloquante non échappable…)

      Cela étant, mes liens sont donc toujours valides, avec des trucs du genre
      {A@cœur1 < data.txt@machine2} | B@cœur2 | C@machine2 > resultat@machine3


      HS : {echo "dodo"; sleep 1; echo "bien dormi"} | echo "pendant ce temps là"
      Zut, ça bouffe la sortie standard de l'un, même quand l'autre ne la consomme pas !
      • [^] # Re: Been there, done that

        Posté par (page perso) . Évalué à 3.

        > pas besoin de créer B tout de suite dans A|B si A met 20 minutes avant de faire la moindre sortie.

        Et si B mouline 20 minutes avant d'être prêt à analyser la moindre sortie ?
        • [^] # Re: Been there, done that

          Posté par (page perso) . Évalué à 1.

          Si vous telechargez les sources, il y a un test (un petit script shell).
          Si vous regardez un peu ce qu'il fait, vous comprendrez comment
          ca marche.

          En gros, vous avez un fichier de commandes a executer.
          Chaque commande est independante des autres (l'ordre, on s'en fiche donc).
          Le script garantie juste que le plus de commandes possibles sont executees en
          parallele sur la meme machine.

          Ce qui ressemble le plus a ce que je fais, c'est xargs -P.
  • # xargs -n 1 -P nb_core

    Posté par (page perso) . Évalué à 1.

    sinon on peut utiliser xargs, par exemple pour restaurer un dump de 1 fichier par table, 4 en // :

    ls *.gz | xargs -n 1 -P 4 -I {} sh -c 'zcat {} | mysql restore'

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.