IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes POSIX Discussion :

Paralléliser des processus fils dans la limite de n


Sujet :

Shell et commandes POSIX

  1. #1
    Membre confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Points : 473
    Points
    473
    Billets dans le blog
    1
    Par défaut Paralléliser des processus fils dans la limite de n
    Bonjour,
    Je voudrais faire une sorte de wait qui se declenche sur la fin de n'importe quel process fils ( le wait attend la fin de tous )
    pour paralleliser n process et en rajouter un des qu'un des n est fini.
    J'ai cherché avec ps, trap et autres mais ce que j'ai trouvé de plus simple a faire est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #!/bin/ksh
    #set -xv
     
    F_jeton=$$.tail
    echo GO > ${F_jeton}
     
    _test() 
    # -------------------------------------------------------------------------- #
    {
      sleep $1
      echo "fin $1" >> ${F_jeton}
      echo "fin $1"
     
    }
    #============================================================================#
     
    for i in 30 5 10 20 5 15 25
    do
      _test $i &
     
      tail -1f ${F_jeton} |
      while read -r a
      do
        #NB=$(ps --ppid $$ |wc -l)
        NB_JOBS=$( jobs -l | wc -l )
        echo "V=$i  NB=$NB_JOBS"
     
       [[ $NB_JOBS -lt 6 ]] &&  
        break
     
      done
    done
     
    wait
    Mais ici le nombre de job rapporté par jobs est le double de mes appels à _test ...
    j'ai donc mis 6 comme limite pour en avoir 3 en // .
    Y a t il plus simple ? plus clair ? quelqu'un sait pour quoi j'ai deux jobs par appel à ma fonction ?

    MERCI

  2. #2
    Expert éminent sénior
    Avatar de Escapetiger
    Homme Profil pro
    Administrateur système Unix - Linux
    Inscrit en
    Juillet 2012
    Messages
    1 477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Administrateur système Unix - Linux

    Informations forums :
    Inscription : Juillet 2012
    Messages : 1 477
    Points : 11 057
    Points
    11 057
    Par défaut
    Citation Envoyé par Jean.Cri1 Voir le message
    Mais ici le nombre de job rapporté par jobs est le double de mes appels à _test ...
    j'ai donc mis 6 comme limite pour en avoir 3 en // .
    Y a t il plus simple ? plus clair ? quelqu'un sait pour quoi j'ai deux jobs par appel à ma fonction ?
    Bonjour,
    Après les man ksh tail read jobs que j'ai pu lire et non testé ici, il semble que ce soit le echo GO initial dans le fichier $$.tail qui fait que chaque appel ultérieur à tail -lf $$.tail récupère la ligne GO "en plus" à chaque itération de n.
    set -xv devrait te permettre de le voir.

    Après, question simplicité et clarté, ce ne sont pas les experts qui manquent sur DVP , commençons par résoudre pas à pas avant d'affiner / optimiser tes besoins.
    « Developpez.com est un groupe international de bénévoles dont la motivation est l'entraide au sens large » (incl. forums developpez.net)
    Club des professionnels en informatique

  3. #3
    Membre confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Points : 473
    Points
    473
    Billets dans le blog
    1
    Par défaut
    En fait c'est le tail ( probablement a cause du | qui le suit) qui créé un process fils.
    Pour m'affranchir de tous les fils qui ne m'interessent pas, j'appelle maintenant un script pour pouvoir reconnaitre le process

    cat doIt.ksk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #!/bin/ksh
    #set -xv
     
      echo - - - - - $(date "+%T") "DEBUT $1" 
      sleep $1
      echo "fin $1" >> ${F_doIt}
      echo - - - - - $(date "+%T") "FIN   $1"
    cat tst.ksh :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #!/bin/ksh
    #set -xv
     
    echo "===> $$ <==="
    export F_doIt=doIt.tail
    echo GO > ${F_doIt}
     
    for i in 30 5 10 20 5 15 25
    do
      doIt.ksh $i &
     
      tail -1f ${F_doIt} |
      while read -r a
      do
        echo =====================
        Nb_doIt=$( ps --ppid $$ |grep doIt.ksh | wc -l )
        echo "i=$i  NB=$Nb_doIt" $(date "+%T")
        pgrep  -P $$ |xargs ps -f -p |grep doIt.ksh |grep -v grep
       #pgrep  -P $$ |xargs ps -f -p
       [[ $Nb_doIt -lt 3 ]] &&  
        break
      done
    done
     
    wait
    Par contre, j'utilise pgrep -P qui n'est pas forcement sur tous les unix.
    Quelqu'un aurait une autre solution simple pour filtrer/compter les process fils qui m'interessent ?

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par Jean.Cri1 Voir le message
    En fait c'est le tail ( probablement a cause du | qui le suit) qui créé un process fils.
    Pour m'affranchir de tous les fils qui ne m'interessent pas, j'appelle maintenant un script pour pouvoir reconnaitre le process
    Tu cherches à reconnaître les process par leur nom. C'est toujours un peu risqué. La preuve, il faut filtrer les "grep <le_nom>" et si qqn "s'amuse" à créer un process nommé autre_doIt.ksh, tu risques de le reconnaître à tort.

    Si je devais résoudre ton pb, je crois que je prendrais plutôt le numéro du process (le PID) que tu peux récupérer avec $! après le lancement en bg et stocker dans une liste.

    D'où quelque chose comme (non testé!!!):

    cat tst.ksh :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #!/bin/ksh
    #set -xv
     
    echo "===> $$ <==="
    export F_doIt=doIt.tail
    echo GO > ${F_doIt}
     
    list_pid=''
     
    for i in 30 5 10 20 5 15 25
    do
      doIt.ksh $i &
      pid=$!
      list_pid="${list_pid} ${pid}" # pid toujours précédé d'une espace
     
      tail -1f ${F_doIt} |
      while read -r a
      do
        echo =====================
        Nb_doIt=0
        l_pid=''
        for pid in ${list_pid} ; do
          if is_actif $pid # en utilisant "ps" sur la bonne colonne ou bien /procfs ?
          then
          afficher le ps du $pid
          ((Nb_doIt++)
          l_pid="${l_pid} ${pid}" # pid toujours précédé d'une espace
          fi
        done
        list_pid="${l_pid}"
        echo "i=$i  NB=$Nb_doIt" $(date "+%T")
     
       [[ $Nb_doIt -lt 3 ]] &&  
        break
      done
    done
     
    wait

  5. #5
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 842
    Points
    7 842
    Par défaut
    Si tu veux vraiment faire un script portable, il y a d'autres problèmes que le "pgrep" à corriger:

    - "/bin/ksh" n'est pas forcément disponible sur tous les Unix, un script strictement portable ne doit pas spécifier le chemin du shell à utiliser

    - "tail -1f" n'est plus POSIX, il faut utiliser "tail -c 1 -f", mais qui ne marchera pas forcément avec le tail par défaut de ton OS ...

    - "ps --ppid $$" n'est pas portable, on peut par exemple le remplacer par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ps -e -o pid,ppid | awk "\$2==$$"
    - "[[" n'est pas POSIX, utiliser "[" à la place.
    ɹǝsn *sıɹɐlos*

  6. #6
    Membre confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Points : 473
    Points
    473
    Billets dans le blog
    1
    Par défaut
    Merci pour vos remarques,
    Meme si je stocke les pid fils,
    je dois verifier
    - qu'il existe toujours
    - qu'il m'appartient ( il pourrait avoir été reaffecté à quelqu'un d'autre )
    - et qu'il fait bien doIt.ksk ( ce quelqu'un d'autre pourrait meme etre moi meme ... )

    c'est pourquoi j'ai cherché directement ces caracteristiques .

    J'ai réécrit tout ca avec l'option suivi des pid fils et l'option TRAP :
    cat doIt.ksh:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/bin/ksh
    #set -xv
     
      echo + + + $(date "+%T") "DEBUT $1 $$" 
      sleep $1
      echo - - - $(date "+%T") "FIN   $1" 
      kill -USR1 $PPID
      echo "fin $1" >> ${F_doIt}
    #  kill -USR1 $PPID
    cat tst.ksh :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #!/bin/ksh
    #set -xv
     
    echo "===> $$ <==="
    export F_doIt=doIt.tail
    echo GO > ${F_doIt}
     
    typeset -i nb_TRAP=0
    trap ' nb_TRAP=$nb_TRAP-1 ; echo \ \ \X\ \> nb_TRAP=$nb_TRAP' USR1
     
    for i in 30 5 10 20 5 15 25 5
    do
      doIt.ksh $i &
      tab[$!]=$!
      nb_TRAP=$nb_TRAP+1
     
      echo "===== $(date "+%T") : i=$i ===== nb_TRAP=$nb_TRAP | nb_TAB=${#tab[*]} | nb_PS=${nb_PS} "
     
      tail -n 1 -f ${F_doIt} |
      while read -r a
      do
        echo "----- $(date "+%T") : i=$i ----- nb_TRAP=$nb_TRAP | nb_TAB=${#tab[*]} | nb_PS=${nb_PS} "
     
        nb_PS=$( ps -e -o pid,ppid,cmd | awk '$2=="'$$'"' |grep doIt.ksh | grep -v grep |tee /dev/tty |wc -l )
        echo "    > nb_PS=${nb_PS} " 
     
        for doItPid in ${tab[*]}
        do
          ps -o pid,ppid,stime,cmd $doItPid | awk '$2=="'$$'"' | grep doIt.ksh
          [ $? -ne 0 ] && unset tab[$doItPid]
        done
        echo "    > nb_TAB=${#tab[*]}" 
     
    #   [ ${nb_PS} -lt 3 ] &&
    #   [ ${#tab[*]} -lt 3 ] &&
        [ ${nb_TRAP} -lt 3 ] &&
        break
      done
    done
     
    echo "===== $(date "+%T") : i=$i ===== nb_TRAP=$nb_TRAP | nb_TAB=${#tab[*]} | nb_PS=${nb_PS} END for"
     
    # wait
    while [ $nb_TRAP -gt 0 ]
    do
      echo wait
      wait
    done
    J'ai des petites reticences avec le trap parceque
    - je ne l'ai jamais utilisé
    - j'ai un peu l'impression de travailler en aveugle
    - j'ai été obligé de transformer le wait final en boucle car un trap pendant cette commande finissait le script meme s'il reste d'autres fils

    Avez vous des avis sur le trap ( pourquoi il ne reprend pas le wait sur lequel il etait, ne risque t il pas d'interrompre une autre commande qui ne se finirait pas non plus et "casserait" l'algorithme , ne risque-t-on pas d'en rater s'il y en a deux en meme temps ... )

    Quelle methode privilégieriez vous et pourquoi ?

Discussions similaires

  1. Popen : lancer des processus fils
    Par roipoussiere dans le forum Général Python
    Réponses: 13
    Dernier message: 18/01/2014, 08h55
  2. Connexion BD partagée et parallélisation des processus
    Par FrRoulio dans le forum Développement de jobs
    Réponses: 0
    Dernier message: 14/11/2012, 12h10
  3. Réponses: 1
    Dernier message: 05/08/2011, 17h02
  4. détection de la fin des processus fils
    Par SoftAbdou dans le forum Linux
    Réponses: 6
    Dernier message: 15/07/2008, 00h06
  5. Attendre la fin des threads fils d'un processus
    Par SteelBox dans le forum Windows
    Réponses: 15
    Dernier message: 24/02/2006, 16h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo