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 GNU Discussion :

Wait conditionné au nombre de processus


Sujet :

Shell et commandes GNU

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 164
    Par défaut Wait conditionné au nombre de processus
    Bonjour,

    j'ai un script qui lance des traitements sur un serveur (1 à n traitements). Ces traitements sont lancés en parallèle selon un maximum ($maxParallele) qui est positionné à 5 aujourd'hui. Quand un bloc de 5 traitements est terminé, le script lance les 5 suivants. Voici mon code simplifié :

    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
    function fctWait {
        # On wait les processus fils
        wait
        # Si il y a une écriture dans le fichier  des codes retour c'est qu'au moins un processus fils a planté donc on sort en erreur
        if [ -f ${fichierCodeRetour} ] && [ -s ${fichierCodeRetour} ];then
            return 1
        fi
        return 0
    }
     
    function fctExit {
        # On positionne un flag d'erreur dans le fichier des codes retour et on sort en erreur
        echo "1" >> ${fichierCodeRetour}
     
        fctPrintLog "$1"
        exit 1
    }
     
    export PID=$$
    typeset nTraitement=0
    typeset maxParallele=5
    export fichierCodeRetour="${root}/fichierCodeRetour_`date +"%Y%m%d"`_${PID}.tmp"
    > ${fichierCodeRetour}
     
    while read traitement
    do     
        # Si on est au max parallèle on wait et on remet les compteurs à 0
        if [[ "${nTraitement}" -ge "${maxParallele}" ]]; then
            fctWait ${fichierCodeRetour}
            [[ $? -ne 0 ]] && fctExit "ERREUR - Traitement interrompu (wait)"
            nTraitement=0
        fi
     
        {
            [...traitement...]
        } &
     
        ((nTraitement+=1))
     
    done < ${fichierDesTraitements}
     
    # On wait le dernier traitement de la boucle
    fctWait ${fichierCodeRetour}
    [[ $? -ne 0 ]] && fctExit "ERREUR - Traitement interrompu (wait)"
    Je boucle sur un fichier qui contient mes traitements : ${fichierDesTraitements}, je lance 5 processus fils, dès que les 5 sont terminés (wait) je lance les 5 suivants. Si au moins un des fils plante, j'attends que les autres en parallèle se terminent et je stop le script, je ne lance pas les 5 suivants. Pour cela quand un fils sort en erreur je positionne un flag dans un fichier partagé que je vais lire dans la fonction fctWait juste après le wait avant d'éventuellement relancer un bloc.

    Cela tourne en production et fonctionne parfaitement ! j'aimerais maintenant optimiser ce fonctionnement et avoir toujours 5 traitements en parallèle. Je lance 5 processus, un se termine, j'en relance un directement pour en avoir toujours 5 qui tournent. Par contre je veux garder l’arrêt en cas d'erreur. Un processus fils plante, je laisse terminer ceux en cours mais je n'en lance pas un nouveau.

    j'ai fouillé un peu sur le net mais ça a l'air plus compliqué à gérer... Si vous avez des bouts de code ou des idées je suis preneur

    Merci de votre aide.

  2. #2
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Bonjour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fctWait ${fichierCodeRetour}
    Dans cette ligne, ${fichierCodeRetour} est purement rhétorique puisque tu n'utilises pas $1 dans ta fonction.

    Ce n'est pas ta question, mais j'essaie, d'abord, de comprendre ce que tu fais.


    En fait, tu ne fais pas vraiment de parallélisme. Quand 5 tâches sont lancées, le programme attend. Et ta source de traitements est bloquée. Puis tu retournes à 0.

    Comme tu utilises les fichiers comme signaux, est-ce que tu ne peux pas vérifier ce qu'il y a dedans pour autoriser, ou non, le lancement d'une nouvelle tâche (systématiquement à la fin de la première) ?
    Si tu trouves un 0 dans le fichier, un traitement se permet de se lancer.
    Si tu trouves un nombre supérieur à 1, c'est une erreur. Tout s'arrêtera puisque tes 5 tâches tomberont sur le fichier contenant une erreur.
    Si c'est autre chose, le traitement est en cours. (Puisque tu viens d'en finir une, il y a forcément un 0 ou 1+ dans un fichier)

    Cela signifie que si tu as 5 tâches simultanées, tu auras 5 fichiers à vérifier.
    Tu pourrais tout mettre dans un seul fichier, mais il faut se coltiner le "multiplexage" (ligne 1 pour tâche 1, ligne 2 pour tâche 2 ....)

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 164
    Par défaut
    Merci pour ton retour.

    J'ai volontairement simplifié le code et effectivement j'ai enlevé le $1 dans la fonction, mais j'ai exporté la variable "export fichierCodeRetour" donc normalement je peux y accéder depuis la fonction.

    En gros ce que tu me conseilles de faire c'est de virer le "wait" et de me servir du fichier partagé pour simuler un wait ?

  4. #4
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 293
    Par défaut
    Citation Envoyé par Darkcristal Voir le message
    J'ai volontairement simplifié le code et effectivement j'ai enlevé le $1 dans la fonction, mais j'ai exporté la variable "export fichierCodeRetour" donc normalement je peux y accéder depuis la fonction.
    Attention. Bash n'est pas du C++ ou du java. Les fonctions ne sont pas des espaces confinés. Tes variables sont accessibles dans les fonctions même sans export.


    Citation Envoyé par Darkcristal Voir le message
    En gros ce que tu me conseilles de faire c'est de virer le "wait" et de me servir du fichier partagé pour simuler un wait ?
    En gros.
    Mais à la réflexion, n'as-tu pas envie d'utiliser xargs ou gnu parallel sur ta liste de traitement, avec le paramètre -P 5 (5 processus en parallèles); et il se débrouille.
    Là, il faudrait exporter la fonction pour l'utiliser dans xargs.

  5. #5
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    Citation Envoyé par Flodelarab Voir le message
    Mais à la réflexion, n'as-tu pas envie d'utiliser xargs ou gnu parallel
    j'y ai pensé aussi, je sais pas ce qu'il en est de parallel mais si un des threads tombe en erreur xargs lui continue sans broncher, alors que le PO veut expressément stopper les traitements dans ce cas là une fois le pool de threads en cours terminés

    edit: en cherchant un peu on trouve des trucs tout fait assez aboutis à priori, à voir si ça peut être intéressant...

  6. #6
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 354
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 354
    Par défaut
    Bonjour,

    En ksh , on peut faire quelque chose du genre (améliorable) :
    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
    #!/usr/bin/ksh
    typeset -A taskpp
    ZZ=11
    trap 'rg="$!";[[ ${taskpp["$rg"]} = 1 ]] && unset taskpp["$rg"]' SIGCHLD
    while [[ $ZZ -ne 0 ]]
    do
            if [[ ${#taskpp[@]} -ne 3 && $ZZ -ne 0 ]]
            then
                    #ici, on fait la gestion du lancement de ces process ainsi que leur terminaison, si on veut arreter la boucle
                    #suffit de forcer la variable ZZ à 0 mais pour tout process lancer en background, on conserve la ligne juste après (taskpp["$!"]=1)
                    sleep 3 &
                    taskpp["$!"]=1
                    ZZ=$((ZZ-1))
                    echo "restant: $ZZ -- en cours:${#taskpp[@]}"
                    echo ${!taskpp[@]}
            fi
    done
    while [[ ${#taskpp[@]} -ne 0 ]]
    do
            #ici, on gère le résiduel
            echo "en cours: ${#taskpp[@]}"
            echo ${!taskpp[@]}
            sleep 1
    done
    echo "restant: $ZZ"
    echo "en cours: ${#taskpp[@]}"
    ici, le script lance 3 process en parallèle sur une série de 11 process en tout.
    ce qui donne par exemple:
    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
    $ ksh ./xx.sh
    restant: 10 -- en cours:1
    8742
    restant: 9 -- en cours:2
    8742 8743
    restant: 8 -- en cours:3
    8742 8743 8744
    restant: 7 -- en cours:2
    8742 8748
    restant: 6 -- en cours:3
    8742 8748 8749
    restant: 5 -- en cours:3
    8748 8749 8750
    restant: 4 -- en cours:1
    8754
    restant: 3 -- en cours:2
    8754 8755
    restant: 2 -- en cours:3
    8754 8755 8756
    restant: 1 -- en cours:1
    8760
    restant: 0 -- en cours:2
    8760 8761
    en cours: 2
    8760 8761
    en cours: 2
    8760 8761
    en cours: 2
    8760 8761
    en cours: 2
    8760 8761
    restant: 0
    en cours: 0
    Attention, cette méthode ne fonctionne pas en bash, le trap est très mal géré.

Discussions similaires

  1. Limitation du nombre de processus
    Par bcy dans le forum Unix
    Réponses: 2
    Dernier message: 10/02/2009, 11h38
  2. Le nombre de processus en cours avec la distinction "daemon"/"normal"
    Par arnaudperfect dans le forum Shell et commandes GNU
    Réponses: 7
    Dernier message: 31/07/2007, 15h22
  3. Contrôle du nombre de processus JONAS
    Par jynicol dans le forum JOnAS
    Réponses: 5
    Dernier message: 14/05/2007, 13h30
  4. nombre de processus
    Par momeftah dans le forum Administration système
    Réponses: 2
    Dernier message: 15/03/2007, 09h43
  5. Controler un nombre de processus identiques.
    Par ditfau6 dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 24/05/2004, 16h21

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