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 :

thread et exceptions


Sujet :

Python

Vue hybride

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

    Informations forums :
    Inscription : Mars 2008
    Messages : 36
    Par défaut thread et exceptions
    Bonjour a tous,

    Je débute en python et je voudrais savoir s’il était possible de remonter une erreur dans une autre fonction, je m’explique :

    J’ai crée un thread qui exécute tout plein de chose. Ceci dure très longtemps. Je veux donc crée une méthode (stop) pour arrêter ce thread. J’ai regardé les FAQ à ce sujet, mais cela ne me convient pas.

    Voici la forme de mon thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Def run(self):
           Instruction 1 …
           Instruction 2 …
           …
           for test in test_list :
                  instructions…
                  …
                  for …
                         instructions…
                         …
           instructions…
           …
    Je ne veux pas avoir plein de if self._stopevent.isSet(): break après toute les lignes des for. J’ai donc pensé à mettre le premier for dans un try except. Je crée donc une méthode stop qui lève une exception (self.Stop_A_Loop='Stop_A_Loop' definie dans le __init__(self)). Et lorsque que je fais raise STOP_A_LOOP de la méthode stop, le programme ne propage pas cette exception jusqu’au run donc il ne se passe rien. Mais si je fais raise STOP_A_LOOP dans la méthode run cela arrête bien le thread.

    Avez-vous une solution à me proposer ou une autre méthode pour arrêter ce thread ?

    Merci d’avance
    Jean-Michel

  2. #2
    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,

    C'est normal qu'un raise en dehors de la méthode run n'arrête pas le thread, parce que seule la méthode run s'exécute en thread.

    Par contre, il y a une solution: voir le code ci-dessous.

    Principe:
    - on initialise une variable "arretthread" à False
    - on peut la passer à True en appelant la méthode stopthread() de l'extérieur
    - elle est testée dans run(), et quand elle passe à True, cela génère une exception qui termine run() et donc qui termine le thread.

    Dans l'exemple ci-dessous, le thread contient une boucle infinie qui ne s'arrête que lorsque arretthread passe à True. Et on déclenche cette valeur au bout de 5 secondes d'exécution en appelant app.stopthread().

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    import threading
    import time
    import sys
     
    class Monthread(threading.Thread):
     
        def __init__(self):
            threading.Thread.__init__(self)
            # créé la variable qui pourra porter l'ordre d'arrêter le thread
            self.arretthread=False
     
        def run(self):
            try:
                # ...
                # ...
                while True:
                    if self.arretthread:
                        raise ValueError ("message d'erreur")
                # ...
                # ...
            except:
                # ...
                # récupération et impression du message d'erreur
                print u"%s" % sys.exc_info()[1]
                # ...
                # fin de run, donc fin du thread
     
        def stopthread(self):
            self.arretthread=True
     
    print u"début"
    app=Monthread()
    app.start()
    tps=time.time()
    while app.isAlive():
        # arrêt du thread au bout de 5 secondes
        if time.time()-tps > 5:
            app.stopthread()
        time.sleep(0.1)
    print u"c'est fini"
    Tyrtamos

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 36
    Par défaut thread et exceptions
    Bonjour Tyrtamos,

    Merci de m’avoir répondu.
    Je sais que cette méthode fonctionne mais cela ne me conviens pas (je sais que je suis chiant) voila pourquoi :

    Ce qui est dans la boucle met 5 min à s’exécuter or dans ce cas le thread s’arrêt lorsque la boucle se termine donc au bout de 5 min max. donc cela m’oblige de mettre des if pour tester arretthread et faire un break pour sortir de la boucle. Et cela m’embête beaucoup car il y a beaucoup de lignes dans le for. Ce qu’il faudrait c’est lorsque stopthread est appelé cela arrête le thread la ou il est et non qu’il finisse la fin de la boucle pour s’arrêter.

    Mais peut être que les exceptions ne peuvent pas régler ce type de problème.
    As-tu une autre idée ?

    Merci d’avance
    Jean-Michel

  4. #4
    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
    Oui, j'ai une autre solution, elle utilise sys.settrace().

    C'est une fonction utilisée pour le debugging, qui permet de tester la variable à chaque ligne d'instruction python exécutée sans avoir de if dans la méthode run. J'ai trouvé cette solution, parce que je devais arrêter un calcul eval() trop long, et donc que je n'avais pas de boucle pour tester la variable arretthread. Cela marche très bien.

    Mais je n'ai pas le temps maintenant: je te répond ce soir.

    Tyrtamos

  5. #5
    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
    Désolé, je ne retrouve plus cette solution avec settrace.

    Elle s'inspirait de cette solution: http://mail.python.org/pipermail/pyt...ay/260937.html, mais elle était beaucoup plus simple.

    Je continuerai à chercher demain, mais c'est sans garantie.

    Tyrtamos

  6. #6
    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,

    Voilà ce que je te propose:

    1- créer un nouveau module appelé ici "threadatuer" (fichier threadatuer.py) comportant une nouvelle classe dérivée de threading.Thread dotée d'une méthode "tuer()":

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    # source: inspiré de: http://mail.python.org/pipermail/python-list/2004-May/260937.html
     
    import sys
    import threading
     
    ##############################################################################
    class Threadatuer(threading.Thread):
        """Sous-classe de threading.Thread, avec une methode tuer()"""
     
        def __init__(self, *args, **keywords):
            threading.Thread.__init__(self, *args, **keywords)
            self.atuer = False
     
        def start(self):
            self.run_sav = self.run
            self.run = self.run2
            threading.Thread.start(self)
     
        def run2(self):
            sys.settrace(self.trace)
            self.run_sav()
            self.run = self.run_sav
     
        def trace(self, frame, event, arg):
            if self.atuer:
                if event == 'line':
                    raise SystemExit()
            return self.trace
     
        def tuer(self):
            self.atuer = True
    2- Exemple d'utilisation: après importation du module threadatuer, on utilise désormais threadatuer.Threadatuer au lieu de threading.Thread pour créer les classes thread. Ce qui fait qu'on peut désormais tuer le thread actif à n'importe quel moment simplement en appelant sa nouvelle méthode .tuer(). Dans l'exemple ci-dessous, on tue le thread au bout de 5 secondes.

    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
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    # importation fonctionnellement nécessaire
    import threadatuer
     
    # importation seulement nécessaire pour l'exemple
    import time
     
    ##############################################################################
    class Monthread(threadatuer.Threadatuer):
     
        def __init__(self):
            threadatuer.Threadatuer.__init__(self)
     
        def run(self):
            # ...
            k=0
            while True:
                print "k= ",k
                k+=1
            # ...
            # fin de run, donc fin du thread
     
    ##############################################################################
     
    print "lancement du thread"
    app=Monthread()
    app.start()
    tps=time.clock()
    while app.isAlive():
        if (time.clock()-tps) > 5.0: # arrêt du thread au bout de 5 secondes
            app.tuer()
    print "fin du thread"
    time.sleep(2)
    Attention: ce n'est pas compatible avec les outils de développement qui utilisent déjà leur propre trace (comme IDLE).

    J'ai vérifié que ça fonctionnait sur Windows XP et sur Linux (opensuse 10.3).

    Ok?

    Tyrtamos

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

Discussions similaires

  1. Ruby, thread et exceptions
    Par boutintrain dans le forum Ruby
    Réponses: 1
    Dernier message: 20/04/2010, 20h41
  2. Thread.Start : exception OutOfMemory
    Par InfoTdl dans le forum C#
    Réponses: 5
    Dernier message: 21/06/2007, 08h12
  3. [thread] Exception non catchée
    Par mammistegon dans le forum Concurrence et multi-thread
    Réponses: 3
    Dernier message: 22/11/2004, 21h43
  4. [Kylix] exception qtinft.dll et multi-threading
    Par leclaudio25 dans le forum EDI
    Réponses: 3
    Dernier message: 27/03/2003, 18h09
  5. Réponses: 5
    Dernier message: 12/06/2002, 15h12

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