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 :

[Threading] [Pyserial]Problème de fuite mémoire


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau candidat au Club
    Homme Profil pro
    Ingénieur hardware
    Inscrit en
    Mars 2017
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur hardware

    Informations forums :
    Inscription : Mars 2017
    Messages : 2
    Par défaut [Threading] [Pyserial]Problème de fuite mémoire
    Bonjour,

    Je me permet de poster car je dois ré-écrire un programme en python et je débute avec ce langage.

    Mon application, dont le code allégé figure ci-dessous, se charge d'échanger des informations avec un port COM USB. Cette partie fonctionne bien.
    J'ai voulu rajouter une détection de connexion/déconnexion du port COM. Il ne me semble pas que la librairie PYSERIAL permette ce genre de chose, mais je me trompe peut-être. Du coup je fais du polling...

    Ma première question est : Peut-on faire la même chose de manière plus élégante ?

    Pour ce polling, j'ai utilisé maladroitement les Threads,, enfin plus précisément les Timers. Ca fonctionne bien, mais à chaque appel de ma méthode "connexionPIC", la quantité de mémoire occupée par le script python augmente, et après plusieurs heures Windows 7 m'affiche une erreur.
    Je pense que le problème vient du fait que ma fonction s'appelle, d'une certaine façon, elle-même. Un delete bien placé pourrait peut-être solutionner le problème, mais je ne sais pas comment l'utiliser correctement (mais essais sont restés infructueux).

    Ma seconde et dernière question est donc : Comment empêcher cette fuite de mémoire qui, sur le long terme, est pénalisante ? L'utilisation de thread peut-elle être évitée ? (sachant qu'en parallèle, d'autres event de l'utilisateur peuvent survenir)


    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
    class APPLI(object):
     
    	def __init__(self):
    		#Blablabla
    		#...
    		#...
    		self.win.mainloop()
     
    	#Connexion au port com
    	def connexionPIC(self):
    		self.threading = threading
    		self.threading.timer = self.threading.Timer(0.5,self.connexionPIC)
    		self.threading.timer.start()
     
    		VID = 0x04D8
    		PID = 0x000A
     
    		device_list = list_ports.comports()
    		port = None
    		for device in device_list:
    			if(device.vid == VID and device.pid == PID):
    				port = device.device
    				break
    		if (port!=None):
    			print("Port COM trouvé")
     
    test = APPLI()
    test.threading.timer.cancel()
    test.threading.Thread.join
    Merci d'avance pour les pistes que vous saurez me donner !

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 742
    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 742
    Par défaut
    Citation Envoyé par adrien49 Voir le message
    Ma première question est : Peut-on faire la même chose de manière plus élégante ?
    Pas avec PySerial en tous cas.

    Citation Envoyé par adrien49 Voir le message
    Je pense que le problème vient du fait que ma fonction s'appelle, d'une certaine façon, elle-même. Un delete bien placé pourrait peut-être solutionner le problème, mais je ne sais pas comment l'utiliser correctement (mais essais sont restés infructueux).
    C'est une théorie que vous devriez pouvoir tester avec un exemple du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> from threading import Timer
    >>> def f():
    ...     p = Timer(0.5, f)
    ...     p.start()
    ...     print('f')
    ...
    >>> f()
    Soi vous reproduisez le problème et c'est un bug à remonter aux développeurs Python, soit vous ne le reproduisez pas et il faut chercher de quoi se remplit la mémoire.

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

  3. #3
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Le fait que le timer s'appelle lui-même ne me semble pas être une bonne idée.

    En fait, le problème est qu'on veut une surveillance permanente, par exemple en appelant une fonction de test toutes les 0.5 seconde, alors que threading.Timer n'appelle la fonction qu'une seule fois après la durée donnée.

    En ce qui me concerne, j'utilise dans ce cas un thread qui contient l'exécution d'un Timer dans une boucle while. Ainsi, on attend la fin du Timer précédent avant de lancer le suivant.

    Voilà un exemple de code:

    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
    import time
    import threading
     
    class Intervallometre(threading.Thread):
        """permet d'appeler une foncton toutes les x secondes
        """
        def __init__(self, duree, fonction, args=[], kwargs={}):
            threading.Thread.__init__(self)
     
            # stocke les arguments donnés à l'appel
            self.duree = duree
            self.fonction = fonction
            self.args = args
            self.kwargs = kwargs
     
            # pour permettre l'arrêt a la demande
            self.encore = True  
     
        def run(self):
            """ partie exécutée en tâche de fond
            """
            while self.encore:
                self.timer = threading.Timer(self.duree, self.fonction, self.args, self.kwargs)
                self.timer.setDaemon(True)
                self.timer.start()
                self.timer.join() # on attend que le timer ait appelé la fonction
     
        def stop(self):
            """ méthode à appeler pour stopper l'intervallomètre
            """
            self.encore = False  # pour empêcher un nouveau lancement de Timer et terminer le thread
            if self.timer.isAlive():
                self.timer.cancel()  # pour terminer une éventuelle attente en cours de Timer
     
    def test(ch):
        print(ch)
     
    t = time.time()
    intervallometre = Intervallometre(0.5, test, ["toto"])
    intervallometre.start()
     
    # on attend 10 secondes pendant lesquelles la fonction test s'exécute périodiquement
    while time.time() - t <= 10:
        pass
     
    # on stoppe l'intervallometre
    intervallometre.stop()
     
    print("===> FIN")

  4. #4
    Nouveau candidat au Club
    Homme Profil pro
    Ingénieur hardware
    Inscrit en
    Mars 2017
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur hardware

    Informations forums :
    Inscription : Mars 2017
    Messages : 2
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Pas avec PySerial en tous cas.
    Merci pour votre aide. Peut être avez-vous une autre librairie à me suggérer?

    Soi vous reproduisez le problème et c'est un bug à remonter aux développeurs Python, soit vous ne le reproduisez pas et il faut chercher de quoi se remplit la mémoire.
    Après quelques heures à tourner, l'occupation mémoire est toujours à peu près la même. Du coup ce n'est pas ça le problème, mais c'est plutôt lié à mon application.

    Citation Envoyé par wiztricks Voir le message
    Salut,
    Comme vous utilisez un GUI, vous disposez de la possibilité d'ordonnancer l'appel d'une fonction sans passer par les threads (mais elle dépend du GUI que vous utilisez). Mais que cette opération soit lancée par un thread ou par le GUI ne devrait pas changer grand chose côté fuite mémoire (dont la cause reste à déterminer, et pour cela arriver à le reproduire "hors application").
    L'essai précédent semble m'orienter dans ce sens. Je vais refaire une batterie d'essai pour mieux localiser le problème. J'utilise tkinter


    Merci à tyrtamos aussi pour sa solution, que je vais essayer aussi car elle me parait plus "propre".

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 742
    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 742
    Par défaut
    Citation Envoyé par adrien49 Voir le message
    L'essai précédent semble m'orienter dans ce sens. Je vais refaire une batterie d'essai pour mieux localiser le problème. J'utilise tkinter
    Avec tkinter, pour des opérations courtes (et récupérer la liste des interfaces connectées sur un bus devrait être assez rapide), on peut utiliser .after.
    Ce que raconte Tyrtamos est que la durée de traitement pouvant être plus longue que l'attente, il est préférable de d'écrire:
    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
             def connexionPIC(self):
     
    		VID = 0x04D8
    		PID = 0x000A
     
    		device_list = list_ports.comports()
    		port = None
    		for device in device_list:
    			if(device.vid == VID and device.pid == PID):
    				port = device.device
    				break
    		if (port!=None):
    			print("Port COM trouvé")
     
    		self.threading = threading
    		self.threading.timer = self.threading.Timer(0.5,self.connexionPIC)
    		self.threading.timer.start()
    i.e. faire le traitement avant de lancer le Timer suivant histoire qu'on ne se retrouve pas avec plein de traitements simultanés.

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

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 742
    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 742
    Par défaut
    Salut,

    Citation Envoyé par adrien49 Voir le message
    L'utilisation de thread peut-elle être évitée ? (sachant qu'en parallèle, d'autres event de l'utilisateur peuvent survenir)
    Comme vous utilisez un GUI, vous disposez de la possibilité d'ordonnancer l'appel d'une fonction sans passer par les threads (mais elle dépend du GUI que vous utilisez). Mais que cette opération soit lancée par un thread ou par le GUI ne devrait pas changer grand chose côté fuite mémoire (dont la cause reste à déterminer, et pour cela arriver à le reproduire "hors application").

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

Discussions similaires

  1. [OpenOffice][Tableur] problème de fuites mémoires
    Par sephial dans le forum OpenOffice & LibreOffice
    Réponses: 0
    Dernier message: 23/11/2009, 17h26
  2. Problème de fuites mémoire
    Par Le Barde dans le forum C++
    Réponses: 12
    Dernier message: 02/09/2007, 08h49
  3. [VB6] Problème de fuite mémoire
    Par GyLes dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 19/03/2007, 14h58
  4. [C++] problème de fuite mémoire
    Par Cirdan Telemnar dans le forum C++
    Réponses: 26
    Dernier message: 16/06/2006, 10h16
  5. Problème de fuite mémoire sur un idFTP
    Par jeromelef dans le forum Composants VCL
    Réponses: 6
    Dernier message: 26/07/2005, 17h29

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