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 files d'attente]Problème de compréhension


Sujet :

Python

  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut [Thread et files d'attente]Problème de compréhension
    Bonjour, j'ai un problème pour comprendre cette exemple d'utilisation des files d'attente dans Python. Voilà le 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
     
    import threading, Queue
     
    class InterfaceExterne(threading.Thread):
        def __init__(self, externalCallable, **kwds):
            threading.Thread.__init__(self, **kwds)
            self.setDaemon(1)
            self.externalCallable = externalCallable
            self.workRequestQueue=Queue.Queue()
            self.resultQueue = Queue.Queue()
            self.start()
        def request(self, *args, **kwds):
            "Appelee par les autres threads comme le serait externalCallable"
            self.workrequestQueue.put((args,kwds))
            return self.resultQueue.get()
        def run(self):
            while 1:
                try : arg, kwd = self.worRequestQueue.get_nowait()
                except Queue.Empty : pass
                else : self.resultQueue.put(self.externalCallable(*args, **kwds))
    En fait, je n'arrive pas à comprendre le déroulement des opérations :
    Par exemple, si je charge ce fichier dans l'interpréteur et que je réalise les opérations suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    def dire_bonjour_a(nom):
        print 'bonjour' + str(nom)
        return 'j\'ai dit bonjour'
     
    thread_bonjour = InterfaceExterne(dire_bonjour_a)
    thread_bonjour.request('monde')
    Quand un appel à thread_bonjour.request('monde') est fait, j'ai du mal à comprendre comment la file d'attente va fonctionner, parce que je ne comprends pas comment la méthode self.request() peut retourner un résultat si la méthode run() n'a pas pris connaissance de la requête. Pouvez-vous m'expliquer comment cela fonctionne ?

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 465
    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 465
    Points : 9 257
    Points
    9 257
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Le thread ne fonctionne effectivement que lorsque la méthode run() est lancée, et jusqu'à ce qu'elle s'arrête.

    Or, la méthode run est lancée ici avec la méthode start(), elle-même lancée à l'initialisation de la classe.

    Donc, il suffit d'instancier ta classe pour que le thread soit actif. Tu peux d'ailleurs le vérifier avec la méthode .isAlive().

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 119
    Points : 139
    Points
    139
    Par défaut
    Bonjour,

    start est appelée dans l'init, ce qui a pour effet de lancer run dans un autre thread. run regarde en permanence dans la queue s'il y a quelque chose pour lui (ce qui a pour effet de consommer tout le CPU, d'ailleur. Pourquoi pas get plutot que get_nowait?)
    De son coté, la méthode request place quelquechose sur la queue request puis arrive a l'appelle de get(), ce qui a pour effet de la bloquer jusqu'à ce qu'il y ait quelquechose dans la queue result.
    Pendant ce temps, le get_nowait de la queue request retourne quelque chose, le calcul est fait et le tout est mis dans la queue de result (resultqueue.put...).
    Du coup le get() de la méthode request() se débloque, et il retourne le résultat.

    J'espère que ça clarifie??

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    Oui, merci beaucoup. En fait, je n'avais pas réalisé (juste ce matin en lisant le bouquin) que la méthode un_thread.run() lancée par la méthode un_thread.start() est contenue dans un thread à part, complétement séparé des autres méthodes.
    pourquoi get_nowait et pas get
    : c'est une modification personnelle de l'exemple du bouquin due à ma mauvaise compréhension, alors qu'un bon timeout de 2 secondes permettrait d'économiser du temps processeur, c'est noté.

    En fait, en attendant, j'ai décidé d'utiliser un sémaphore.
    (D'ailleurs je me demande si je devrais réécrire mon application , maintenant qu'elle marche tant bien que mal)

    Schématiquement, j'ai deux méthodes, lecture() et ecriture(), et je ne veux pas que les deux interfèrent. Je fais alors :
    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
     
    class Device:
        def __init__(self):
            self.mon_semaphore=threading.BoundedSemaphore(1)
            #suite de l'initialisation
     
        def lecture(self,param):
            self.mon_semaphore.accquire()
            #operations de lecture
            self.mon_semaphore.release()
     
        def ecriture(self,param):
            self.mon_semaphore.acquire()
            #operation d'ecriture
            self.mon_semaphore.release()
    Ces methodes sont appelees depuis le thread principal et un autre thread externe qui fait une operation de lecture toutes les dix secondes.
    Est-ce que cette méthode d'utilisation du sémaphore est correcte, du moment que mon_device=Device est bien une unique variable globale ?

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 119
    Points : 139
    Points
    139
    Par défaut
    C'est en effet l'idée. J'aurais utilisé un Lock ou RLock plutot qu'un Semaphore (RLock permettrait d'appeler Lecture depuis Ecriture par exemple), et puis j'aurais appelé release dans un bloc finally pour éviter de tout bloquer en cas d'erreur.

Discussions similaires

  1. Nombre de threads en file d'attente (ThreadPool)
    Par Link3 dans le forum Windows Forms
    Réponses: 1
    Dernier message: 05/09/2008, 14h31
  2. problème de file d'attente
    Par dingjianboy dans le forum C++
    Réponses: 4
    Dernier message: 13/06/2008, 20h31
  3. [LabView 8.5][Débutant] Problème file d'attente
    Par yoann23 dans le forum LabVIEW
    Réponses: 20
    Dernier message: 27/03/2008, 18h55
  4. [Continuum] Problème de file d'attente
    Par dev09 dans le forum Intégration Continue
    Réponses: 9
    Dernier message: 13/12/2007, 16h09
  5. [Problème de Compréhension] Les Threads
    Par Identifiant dans le forum Concurrence et multi-thread
    Réponses: 3
    Dernier message: 29/12/2006, 20h00

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