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

Python Discussion :

Utilisation de mémoire excessive


Sujet :

Python

  1. #1
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut Utilisation de mémoire excessive
    Bonjour,

    Dans le cadre d'un projet d'intercommunication entre système d'information, nous avons développé un serveur d'intercommunication multi thread.
    Le principe de ce logiciel est de traiter des messages d'échange de données soit en émission soit en réception.

    Les messages au format texte sont déposés dans des dossiers de réception ou émission.

    Voici mon problème :
    Bien que le logiciel réponde parfaitement a ce qu'il doit faire au moment ou il doit le faire, nous avons constaté qu'il monte en mémoire.
    En effet, alors qu'il traite uniquement des messages de quelques kiloOctet (environ 10ko par message), le programme fini après un temps d'utilisation de plusieurs mois (1 à 2 mois) (oui, je sais c'est un temps long) a prendre plus 50% des ressources mémoire de la machine (4Go de RAM disponible).
    Ceci a pour effet de générer du swap.
    Pour faire une comparaison, il utilise plus de mémoire qu'un serveur d'application zope2 qui tourne en continu aussi et est fortement sollicité.

    Nous avons réécrit une partie du code pour implanté des del de variables, mais rien n'y fait.

    Auriez vous une piste, des idées d'expertises pour arriver à trouver d'où vient le problème.

    Info technique :
    Pateforme : débian 5, 4Go RAM
    Version python : 2.5.2
    l'application est lancée sous forme de service linux

    voici le code principal :
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    #!/usr/bin/python
    import datetime,BaseHTTPServer
    import HL7Passerrelle
    import time
    import os, shutil
    import threading
    import dxLab
     
    VERSION=open(os.path.dirname(os.path.realpath(__file__))+'/version.txt','r')
    __Name__="PERINAT_INTERCOM_SERVER"
    __version__=''.join(VERSION.readlines())
    __port__=34672
     
    def directoryCheck():
        '''verifie que les dossiers de travail sont presents, sinon creation'''
        curdir=os.path.dirname(os.path.realpath(__file__))
        print curdir
        listDossier=['IN',#dossier de reception identite/mouvement
        'OUT',#dossier de sortie
        'TRASH',#corbeille
        'TEMP',#Dossier temporaire
        'IN_LABO',#Dossier de reception des resultats de labo
        'OUT/acte_pratique',#dossier de sortie activite
        'OUT/compte_rendu',#Dossier de sortie CR
        'OUT_PURGE',#dossier de sortie des purge SQL
        'ERROR',#Dossier de sortie en cas d'erreur de traitement
        'ERROR/LABO',#Dossier de sortie des erreur de traitement LABO
        'ERROR/IDT_MVT',#Dossier de sortie des erreur de traitement IDT_MVT
        'LOG'#dossier de sauvegarde de log
        ]
        for path in listDossier:
            try:
        	   os.mkdir('%s/%s' %(curdir,path))
               print "--> %s/%s : CREATED" %(curdir,path)
            except:
        	   print "--> %s/%s : ALREADY EXIST" %(curdir,path)
     
     
    def logfileCheck():
        """Met en archive les fichiers log,
        Cree de nouveaux fichiers pret a l'emploi"""
        listFile=['IDT_MVT','LABO','ACT','CR']
     
        curdir=os.path.dirname(os.path.realpath(__file__))
        t=str(time.time())
     
        try:
    	    os.mkdir('%s/LOG' %(curdir))
        except:
            pass
     
        for f in listFile:
     
            try:
                shutil.move('%s/LOG/%s.log' %(curdir,f),'%s/LOG/%s_%s.log' %(curdir,f,t))
                print "--> %s/LOG/%s : MOVED" %(curdir,f)
            except:
                print "--> %s/LOG/%s : NOT EXIST" %(curdir,f)
     
            F=open('%s/LOG/%s.log' %(curdir,f),'w')
            F.close()
            print "--> %s/LOG/%s : CREATED" %(curdir,f)
     
     
     
    def IDT_MVT():
        HL7Passerrelle.identiteMvt()
        print "--> IDT_MVT THREAD RUNNING"
     
    def OUT_MSG():
        HL7Passerrelle.traitementOUT()
        print "--> OUT_MSG THREAD RUNNING"
     
    def LABO():
        dxLab.traitement()
        print "--> LABO THREAD RUNNING"
     
    try:
        from asyncore import dispatcher
        import sys, time, socket
    except Exception,e:
        print e
    class Server( dispatcher ):
          def __init__(self,port=5000):
                dispatcher.__init__(self)
                self.create_socket( socket.AF_INET, socket.SOCK_STREAM )
                self.bind( ( '', port ) )
                self.listen(1)
     
    if __name__ == '__main__':
       print "%s %s" %(__Name__,__version__)
     
       try:
            Server(port=__port__)
            print "==> SERVER RUNNING : PORT ==> %s" %(str(__port__))
            directoryCheck()#verification des dossiers
            logfileCheck()#verification des fichiers log
            a=0
            while a<2:
                th1=threading.Thread(group=None,target=IDT_MVT)
                th1.start()
                th2=threading.Thread(group=None,target=OUT_MSG)
                th2.start()
                th3=threading.Thread(group=None,target=LABO)
                th3.start()
     
                del th1,th2,th3
                time.sleep(0.5)
       except Exception,e:
            print "==> SERVEUR ALREADY RUNNING"
            print "    Patientez, abandon de demarrage"
            time.sleep(3)
            sys.exit()
    merci d'avance pour vos idées

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Que racontent les outils du module gc?
    Quels sont les objets/modules qui occupent la mémoire?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    bon alors je me suis tourné vers gc, mais comme je connais pas, j'ai juste fait :là, je vois bien qu'en forcant le gc, j'ai a chaque boucle un gc.collect()=11

    Pour vérifier l'hypothèse que ce nombre augmente si je ne fait pas de gc.collect() je le déclenche après 19 itérations et là je vous gc.collect()=544

    J'ai donc laissé le gc.collect() à la fin de chacune de mes itérations et relancé le service pour voir si j'ai encore une montée en charge de la mémoire.

    Ce matin j'ai regardé donc l'utilisation mémoire de mon processus. Je constate qu'après 3 jours de fonctionnement j'en suis déjà a 10% de mémoire utilisée. Ce n'est pas normal, je ne devrait pas excéder le 2 à 3 % maxi.

    Donc il faut que je trouve plus d'informations.
    Comment arriver a récupérer plus d'information (type d'objet collecté par gc par exemple)
    Faut il entrevoir l'utilisation de Process plutôt que threading ?
    J'avoue que c'est un peu nébuleux !

    merci d'avance pour votre aide.

  4. #4
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    je viens d'implanter un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print gc.set_debug(gc.DEBUG_LEAK)
    après chaque itération
    voici le retour :
    --> IDT_MVT THREAD RUNNING
    --> OUT_MSG THREAD RUNNING
    --> LABO THREAD RUNNING
    gc: collectable <cell 0xc66440>
    gc: collectable <weakproxy 0xc32d08>
    gc: collectable <cell 0xc66f30>
    gc: collectable <tuple 0xc2d878>
    gc: collectable <function 0xc68500>
    gc: collectable <tuple 0xc64410>
    gc: collectable <cell 0xc66830>
    gc: collectable <tuple 0xc64990>
    gc: collectable <function 0xc68578>
    gc: collectable <dict 0xc55b20>
    gc: collectable <dict 0xc60940>
    gc: collectable <cell 0xc66c58>
    gc: collectable <weakproxy 0xc32c58>
    gc: collectable <cell 0xc66408>
    gc: collectable <tuple 0xc2d8c0>
    gc: collectable <function 0xc685f0>
    gc: collectable <tuple 0xc64b50>
    gc: collectable <cell 0xc66e50>
    gc: collectable <tuple 0xc64c10>
    gc: collectable <function 0xc68668>
    gc: collectable <dict 0xc54dc0>
    gc: collectable <dict 0xc53110>
    gc: collectable <cell 0xc66e18>
    gc: collectable <weakproxy 0xc32cb0>
    gc: collectable <cell 0xc66638>
    gc: collectable <tuple 0xc2d908>
    gc: collectable <function 0xc686e0>
    gc: collectable <tuple 0xc64c50>
    gc: collectable <cell 0xc66328>
    gc: collectable <tuple 0xc64d50>
    gc: collectable <function 0xc68758>
    gc: collectable <dict 0xc53730>
    gc: collectable <dict 0xc544e0>
    None
    comment interpréter ce résultat?

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,
    Citation Envoyé par airod Voir le message
    Ce matin j'ai regardé donc l'utilisation mémoire de mon processus. Je constate qu'après 3 jours de fonctionnement j'en suis déjà a 10% de mémoire utilisée. Ce n'est pas normal, je ne devrait pas excéder le 2 à 3 % maxi.
    Comment regardez vous la mémoire utilisée?

    A priori, il n'y a pas de bonnes raisons(*) pour que Python rende la mémoire virtuelle allouée. Espérant pouvoir la ré-allouer "plus tard", l'OS ne garde en mémoire (RAM = working set) que les "pages" accédées récemment.

    Au bout d'un certain temps (X jours), la mémoire virtuelle "consommée" devrait tendre vers une asymptote - sinon il faudrait re-booter de temps en temps.

    gc.collect ne semble pas montrer d'anomalies (sur la période).
    Reste à savoir si vous regardez des choses "normales" et "acceptables" ou si vous n'avez pas attendu assez longtemps.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    On peut aussi vérifier si gc.garbage est vide ou pas (cette liste contient tous les objets qui ne sont pas libérables par gc, normalement des dépendances cycliques avec des objets comportant une fonction __del__)…

    Et en py3.3, on a sys._debugmallocstats(), qui donne de bonnes info bas niveau sur l’utilisation mémoire de cpython.

  7. #7
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    lorsque je fait un ... ... après mon gc.collect(), j'obtiens une liste vide. Ce ci montre bien que le gc détruit bien tous les objets.

    Par contre je me pose la question à savoir si a chaque itération, la fonction appelée par un thread est bien détruite ainsi que toutes les variables déclarés lors de son exécution. Il y a t il un moyen de savoir cela?!


    Je continu a chercher ...
    Ce matin l'utilisation mémoire est a 18% alors même qu'aucun message n'a été traité entre hier après midi et ce matin.

    Je ne vois vraiment pas pourquoi j'ai une telle montée en charge.

  8. #8
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Ah, je viens de regarder le code un peu plus attentivement, et… Y a un os (à ronger)*!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
            a=0
            while a<2:
                th1=threading.Thread(group=None,target=IDT_MVT)
                th1.start()
                th2=threading.Thread(group=None,target=OUT_MSG)
                th2.start()
                th3=threading.Thread(group=None,target=LABO)
                th3.start()
     
                del th1,th2,th3
                time.sleep(0.5)
    Je n’étais pas sûr du comportement d’un objet Thread quand on le supprime, et je viens donc de vérifier*: ça ne détruit pas le thread, pour l’excellente raison qu’il est aussi stocké par le module lui-même (et accessible par threading.enumerate()).

    Il faut donc joindre les threads, pour s’assurer qu’ils sont fini, avant d’en lancer d’autres (et pas besoin de les del explicitement)*! Le code correct serait*:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
            a=0
            while a<2:
                th1=threading.Thread(group=None,target=IDT_MVT)
                th1.start()
                th2=threading.Thread(group=None,target=OUT_MSG)
                th2.start()
                th3=threading.Thread(group=None,target=LABO)
                th3.start()
     
                th1.join()
                th2.join()
                th3.join()
     
                time.sleep(0.5)
    Maintenant, je doute un peu (beaucoup) que cela explique ce problème de mémoire, mais difficile d’être sûr, vu qu’on ne sait pas ce que font les targets.

    Autre point qui m’échappe*: d’après ce que je comprends de la fonction “main”, ce script est lancé régulièrement, s’exécute, et s’arrête assez rapidement*? Du coup, qu’advient-il du Server, il est détruit en même temps, j’imagine (surtout que l’objet n’est pas lié dans l’espace local)*? Bref, jamais utilisé asyncore, donc je dois louper quelque chose…

  9. #9
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Il serait aussi intéressant de voir ce que renvoie un appel à len(gc.get_objects()), si le nombre d’objets suivis augmente (significativement) au cours du temps…

  10. #10
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    Oui, alors après avoir échangé avec un collège qui ne code pas python, il m'a mis sur la piste d'une mauvaise gestion des variables stockant les instances des Threads.
    En effet dans le code initial, la déclaration de mes threads se fait à chaque boucle. Ainsi j'ai une assignation en cascade de th1=... alors même que le premier th1 est encore vivant (isAlive())
    Ca rejoint ce que tu dis mont29, les threads mort ne sont pas detruits et donc je consomme de la mémoire.
    J'ai donc modifier le code comme suit :
    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
     
    if __name__ == '__main__':
       print "%s %s" %(__Name__,__version__)
     
       try:
            Server(port=__port__)
            print "==> SERVER RUNNING : PORT ==> %s" %(str(__port__))
            directoryCheck()#verification des dossiers
            logfileCheck()#verification des fichiers log
     
            th1=threading.Thread(group=None,target=IDT_MVT)
            th1.start()
            th2=threading.Thread(group=None,target=OUT_MSG)
            th2.start()
            th3=threading.Thread(group=None,target=LABO)
            th3.start()
            while True:
     
     
                if not th1.isAlive():
                    th1.run()
                else:
                    print 'th1 is alive'
     
                if not th2.isAlive():th2.run()
                else: print 'th2 is alive'
     
                if not th3.isAlive():th3.run()
                else: print 'th3 is alive'
     
                time.sleep(0.5)
     
       except Exception,e:
            print "==> SERVEUR ALREADY RUNNING"
            print "    Patientez, abandon de demarrage"
            print e
            time.sleep(3)
            sys.exit()
    On voit bien là que mes thread sont créés avant la boucle while. Je teste uniquement dans la boucle si le thread doit être relancé ou pas.

    Ca fait 30 minutes que j'ai fait la modif et pour l'instant la consommation mémoire ne grimpe pas. (stable a 0.3% de la mémoire)
    Il est un peu tôt pour tiré la conclusion finale, mais je crois bien que l'explication est logique.

    merci

  11. #11
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut

    Autre point qui m’échappe*: d’après ce que je comprends de la fonction “main”, ce script est lancé régulièrement, s’exécute, et s’arrête assez rapidement*? Du coup, qu’advient-il du Server, il est détruit en même temps, j’imagine (surtout que l’objet n’est pas lié dans l’espace local)*? Bref, jamais utilisé asyncore, donc je dois louper quelque chose…
    Le programme est lancé comme service linux, il s'exécute en permanence.
    Server reste donc actif tant que le service est démarré. Il est détruit lorsque le service est arrêté.

  12. #12
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Pff, j’étais pas réveillé ce matin… Ce code*:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
            a=0
            while a<2:
                th1=threading.Thread(group=None,target=IDT_MVT)
                th1.start()
                th2=threading.Thread(group=None,target=OUT_MSG)
                th2.start()
                th3=threading.Thread(group=None,target=LABO)
                th3.start()
     
                del th1,th2,th3
                time.sleep(0.5)
    …avait en fait pour effet de relancer trois nouveaux threads toutes les demi secondes*! Je m’étais persuadé que a était incrémenté à chaque while, du coup 6 threads étaient lancés et le programme principal était terminé, mais en fait non*! Pas étonnant (si les threads ont une durée de vie certaine) que ça devienne mémorivore*!

    Pour en revenir à ton dernier code, il n’est pas encore idéal, amha… Normalement, une fois qu’un thread est terminé, on n’a pas le droit de le relancer avec un nouveau run. Du coup, je ferais plutôt*:

    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
    if __name__ == '__main__':
       print "%s %s" % (__Name__, __version__)
     
       try:
            Server(port=__port__)
            print "==> SERVER RUNNING : PORT ==> %s" % str(__port__)
            directoryCheck()  #verification des dossiers
            logfileCheck()  #verification des fichiers log
     
            th1 = threading.Thread(group=None, target=IDT_MVT)
            th1.start()
            th2 = threading.Thread(group=None, target=OUT_MSG)
            th2.start()
            th3 = threading.Thread(group=None, target=LABO)
            th3.start()
            while True:
                time.sleep(0.5)
     
                if not th1.isAlive():
                    # Si th1 est termine, on en relance un nouveau (l'ancien objet sera supprime par le gc automatiquement).
                    th1 = threading.Thread(group=None, target=IDT_MVT)
                else:
                    print 'th1 is alive'
     
                if not th2.isAlive():
                    th2 = threading.Thread(group=None, target=OUT_MSG)
                else:
                    print 'th2 is alive'
     
                if not th3.isAlive():
                    th3 = threading.Thread(group=None, target=LABO)
                else:
                    print 'th3 is alive'
     
       except Exception,e:
            print "==> SERVEUR ALREADY RUNNING"
            print "    Patientez, abandon de demarrage"
            print e
            time.sleep(3)
            sys.exit()

  13. #13
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    mouais, d'accord ...
    Tu dis que les instance de thread sont garder dans le module lui même, donc pourquoi ne pas réutiliser une instance en sommeil? Là j'avoue que je comprend pas!

    Bref, si je reprend ton code il manquerait un th*.start() aprés l'instanciation?

    Je vais refaire une passe sur le code et optimiser tout ca!

    En tout cas merci.

  14. #14
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Si l'objet de ces threads est de relancer la même activité à chaque fois, pourquoi ne pas faire cela plus bas?

    On pourrait avoir les activités IDT_MVT, OUT_MSG, LABO comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def some_action(count):
        while count > 0:
            kprint ('name: %s, count=%d' % (threading.current_thread().name, count))
            time.sleep(0.1)
            count -= 1
    Au dessus, on place une fonction redo qui "relance" après un certain temps.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def redo(action, *args):
        all_done = threading.all_done
        while not all_done.is_set():
            try:
                action(*args)
            except:
                raise
        kprint ('%s: exit' % threading.current_thread().name)
    Et on ne crée les threads qu'une seule fois via:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            t = threading.Thread(target=redo,
                                 args=(some_action, 3),
                                 name='t%d' % x)
    => çà permet d'avoir des "activités" pouvant (éventuellement) être relancées sans avoir à recréer le thread opération toujours "coûteuse".
    Le code complet:
    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
    import threading
    threading.all_done = threading.Event()
     
    import time
     
    klock = threading.Lock()
    def kprint(s):
        with klock:
            print(s)
     
    def some_action(count):
        while count > 0:
            kprint ('name: %s, count=%d' % (threading.current_thread().name, count))
            time.sleep(0.1)
            count -= 1
     
    def redo(action, *args):
        all_done = threading.all_done
        while not all_done.is_set():
            try:
                action(*args)
            except:
                raise
        kprint ('%s: exit' % threading.current_thread().name)
     
    if __name__ == '__main__':
        threads =  []
        for x in range(3):
            t = threading.Thread(target=redo,
                                 args=(some_action, 3),
                                 name='t%d' % x)
            t.start()
            threads.append(t)
     
        # on attend un peu
        time.sleep(3)
        threading.all_done.set()
        for t in threads:
            t.join()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Membre éprouvé

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Points : 1 273
    Points
    1 273
    Par défaut
    Non, si thx.isAlive() revoie False, le thread n’existe plus au niveau système, il est terminé. Son objet “représentatif” ne sert donc plus à rien.

    De plus, appeler run() directement revient à exécuter la cible dans le thread principal, c’est start() qui se charge de créer un thread au niveau système et d’y exécuter run(). Et comme on ne peut pas appeler start() plus d’une fois par objet Thread…

    En fait, la partie dans la boucle while sert uniquement à relancer un nouveau thread, si l’un de ceux lancés au début venait à se terminer (c-à-d si la cible se termine, pour une raison ou pour une autre).

    [Edit] message rédigé en même temps que celui de wiztricks.

  16. #16
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    Hummm, merci pour le code Wiztricks. Evidement, déplacer le loop dans le target de chaque Thread est plus propre que de faire un loop qui crée à chaque fois un Thread.

    Merci

  17. #17
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par airod Voir le message
    Hummm, merci pour le code Wiztricks. Evidement, déplacer le loop dans le target de chaque Thread est plus propre que de faire un loop qui crée à chaque fois un Thread.

    Merci
    De rien, un forum sert à poster et y récupérer des idées.
    Vous n'avez rien dit sur les relations entre les différentes activités (les IDT_MVT, OUT_MSG, LABO).
    Je ne sais pas comment est réalisé "threading" en 2.5.
    Une chose est sûre: th.run() après que le thread ait été terminé lève une exception en 2.7 et + car l'attribut self.__target a été détruit à la sortie.
    Cà permet de libérer les éventuelles ressources associées.
    Mais, la discussion ne permet pas encore de dire, si:
    • il y a un "vrai" problème, i.e. la mémoire virtuelle allouée ne tend pas vers son asymptote et explosera,
    • ce problème est du côté de threadings,

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  18. #18
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Points : 891
    Points
    891
    Par défaut
    Ce que je peux dire c'est qu'avant la modification faite à mon code initial pour déplacer les loops au niveau des targets et n'instancier qu'un thread, c'est que sur ma machine de test au démarrage du service l'utilisation mémoire est de 0,3%, au bout de 24h était à environ 10%, puis environ 20% à 72h.

    Après, et cela au bout de 24 h je suis toujours a 0,3%.

    On peut en tirer des conclusions assez simple, non !?


  19. #19
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par airod Voir le message
    On peut en tirer des conclusions assez simple, non !?
    Ca va dans le bon sens et vous pouvez passer les modifications en "prod".
    Pour ce qui est de conclure, il faudra (peut être | sans doute) attendre N semaines d'activité en "prod".
    Il serait peut être sage d'ajouter une mécanique "dumpe" à volonté ou à intervalles réguliers l'état de la mémoire: çà permettrait d'avoir du grain à moudre "just in case".

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 30/04/2008, 16h29
  2. [Memoire] Comment savoir qui utilise la mémoire?
    Par zoltix dans le forum Windows Serveur
    Réponses: 6
    Dernier message: 31/12/2007, 17h55
  3. Consommation Mémoire Excessive – Ca urge
    Par Bronks dans le forum MS SQL Server
    Réponses: 7
    Dernier message: 10/12/2007, 10h40
  4. Connaitre l'utilisation CPU/mémoire
    Par Flophx dans le forum Administration système
    Réponses: 5
    Dernier message: 09/02/2007, 11h40
  5. Réponses: 3
    Dernier message: 12/12/2006, 14h40

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