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 :

Où trouver de l'info pour comprendre le threading avec Python ?


Sujet :

Python

  1. #1
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut Où trouver de l'info pour comprendre le threading avec Python ?
    Bonjour,

    Depuis septembre 2009 que je m'initie au superbe langage Python, je me dis qu'il est temps d'attaquer cette matière passionnante que sont les Threads, après avoir passé des semaines à faire connaissance avec les fondamentaux du langage et les widgets faciles à prendre en main de Tkinter.

    Je commence mes recherches sur le net (en anglais, français et italien) sur ce sujet, et là, patatraf : le contenu des moteurs de recherche contenant des tutoriels python ou des didacticiels complets sur le threading (basique ou avancé) me semble bien maigre ?

    Je ne suis nulle part avec ça...

    Quels conseils ou liens intéressants pourriez-vous donner à un débutant en Python pour entrer dans le monde des Threads ?
    Quel livre utiliser ? Quel site intéressant ? Quel petit script magique pour bien comprendre ?

    Merci d'avance pour vos avis...

  2. #2
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Points : 970
    Points
    970
    Par défaut
    bonjour,

    je m'étais un peu amusé avec ce script. il n'est pas de moi, et je ne me souviens pas où je l'ai trouvé sur la toile:

    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
    #-*- coding:Utf-8 -*-
    import random
    from Queue import *
    from threading import Thread
    import time
     
    enStock = Queue(10)#notre pile, qui peut contenir 10 éléments max( 0 pour enlever la limite)
     
    class Magasin(Thread):
        """ Le 'producteur' : va remplir ses rayons de paquets de schtroumpfs """
        def __init__(self):
            self.ouvert = True
            Thread.__init__(self)
     
        def run(self):
            while self.ouvert :
     
                while not enStock.full() :
                    try :
     
                        enStock.put("ajout d'un paquet de schtroumpf",True,1000)
                        ### le Magasin va ajouter un paquet dans le rayon, et s'il y a plus de place,
                        ### va attendre pendant 1 seconde qu'un paquet soit acheté .
                    except Full,e :
                        print(" Il n'y a pas de place pour un paquet ! ");
     
                    else:
                        print(" On ajoute un paquet de schtroumpfs dans le rayon")
     
                time.sleep(10)
                #on attend 10 secondes avant que le magasin aille alimenter le rayon
     
    class Client(Thread):
        """ le consommateur, va prendre un/des paquet(s) de schtroumpf """
        def __init__(self,faim,numero):
            self.jAiFaim = faim
            self.numero = numero
            Thread.__init__(self)
        def run(self):
            while self.jAiFaim :
                time.sleep(1)
                #le client arrive au bout d'une seconde au rayon
     
                ok=False
                paquet = random.randint(1,4)
                #nombre de paquet qu'il va prendre
                i=1
                print(" Le client n° "+str(self.numero)+" veut "+str(paquet)+" paquet(s) de schtroumpfs")
                while i<=paquet :
                    try:
                        enStock.get(True,500)
                        ok = True
                        print(" n° "+ str(self.numero) + " : Prend un paquet")
     
                    except Empty, e:
                        ok = False
                        break
                    else:
                        i+=1
                if ok :
                    print(" Il reste " + str( enStock.qsize() ) +" paquet(s) de schtroumpfs")
                else :
                    print(" n° "+ str(self.numero) + " : Il n'y a pas assez de paquets")
                self.jAiFaim = False
     
    if __name__=='__main__':
        magasin = Magasin()
        magasin.ouvert = True
        print("##### Le magasin ouvre ses portes #####")
        magasin.start()
     
        i=1
        while i < 10:
            Client(faim = True ,numero = i).start()
            i=i+1
     
        time.sleep(60)
        magasin.ouvert=False
        print("##### Le magasin ferme ses portes #####")

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

    Pour sources d'inspiration.

    Je me suis un peu amusé avec les threads (module threading), et j'en ai fait quelques tutos.
    Ce n'est pas forcément une programmation géniale, mais ça respecte le manuel, c'est assez documenté et ça marche:

    http://python.jpvweb.com/mesrecettes...ion_par_thread

    J'ai aussi utilisé les threads pour faire une petite calculatrice de démo en script CGI sur un serveur Python local:

    http://python.jpvweb.com/mesrecettes...lculatrice_cgi

    J'ai enfin une plus grosse calculatrice graphique (tkinter) dont les calculs sont faits dans un thread, et dont le source est disponible:

    http://python.jpvweb.com/mesrecettespython/calculext

    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

  4. #4
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Merci Kango et Tyrtamos pour vos propositions de liens et de scripts fort intéressants...

    Je me lance alors, puisque j'ai deux personnes aimables qui ont l'air d'être calé dans le threading !


    J'aime bien voir quelquechose de concret (exemple un objet dans un canvas) qui symbolise l'activité du thread...

    Je me suis lancé dans un exemple multi-thread créé de mes petites mains, en étudiant vos exemples et la FAQ de Developpez.com.

    But : essayer d'en voir plusieurs en fonctionnement simultané. Voici ce que cela donne (attention, ça plante dans IDLE, je sais pas trop pourquoi ?) :

    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
    #!/usr/local/bin/python
    # -*- coding:utf-8 -*-
    from Tkinter import *
    import threading
    import time
    from math import *
     
    class ObjetTournant(threading.Thread):
        def __init__(self, x, y, dans_canvas, ray, couleur):
            threading.Thread.__init__(self)
            self.rayon = ray
            self.x0 = x
            self.y0 = y
            self.coul = couleur
            self.angle = 0
            self.c = dans_canvas
            self.Terminated = False
            self.ref = self.c.create_line(self.x0,self.y0, self.x0+self.rayon, self.y0, width = 8, fill=self.coul)
     
        def run(self):
            self.angle = 0
            while not self.Terminated:
                new_x = self.x0 + self.rayon * sin (radians(self.angle))
                new_y = self.y0 + self.rayon * cos (radians(self.angle))
                self.c.coords(self.ref,self.x0,self.y0,new_x,new_y)
                self.angle += 1
                if self.angle > 360:
                    self.angle = 0
                time.sleep(0.01)
            print "Le thread ",self.coul," se termine proprement."
     
        def stop(self):
            self.Terminated = True
     
    class Application:
        def __init__(self):
            self.root=Tk()
            self.root.title('Objets tournant')
            self.root.geometry('600x400')
            self.root.protocol("WM_DELETE_WINDOW", self.finirapplication)
     
            self.c = Canvas(self.root, bg="white")
            self.c.pack(side=TOP, expand=YES, fill=BOTH)
     
            self.listeDesObjetsTournant = []
     
            self.listeDesObjetsTournant.append(ObjetTournant(100,200,self.c, 50, "red"))
            self.listeDesObjetsTournant.append(ObjetTournant(500,100,self.c, 30, "green"))
            self.listeDesObjetsTournant.append(ObjetTournant(340,200,self.c, 40, "blue"))
            self.listeDesObjetsTournant.append(ObjetTournant(200,100,self.c, 80, "black"))
            for obj in self.listeDesObjetsTournant:
                obj.start()
     
            self.root.mainloop()
     
        def finirapplication(self):
            for obj in self.listeDesObjetsTournant:
                obj.Terminated = True
                obj.stop()
            sys.exit()
     
    if __name__ == "__main__":
        app = Application()
    Je ne suis pas encore arrivé à trouver une solution pour placer des boutons de contrôle (démarrer, pause, arrêt) pour manipuler chaque objet tournant indépendamment.

    Mais j'ai quelques questions qui me turlupinent :

    - est-ce que ce code ci-dessus est correct ? (parce qu'il plante souvent mon IDLE, et même parfois l'exécutable python lui-même, carrément !)

    - quelle est la nature profonde de thread.start() : est-ce que cela veut dire qu'un thread ne démarre jamais QU'UNE SEULE FOIS ?

    - quelle est la nature de thread.stop() : est-ce que cela veut dire qu'un THREAD s'arrête définitivement ?

    Où mes deux dernières questions ne sont-elles que des choix qui doivent être fait par le développeur lui-même, en fonction des objectifs de ses threads ?

  5. #5
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    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 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par calogerogigante Voir le message
    est-ce que ce code ci-dessus est correct ? (parce qu'il plante souvent mon IDLE, et même parfois l'exécutable python lui-même, carrément !)
    Comme idle est écrit en python et tkinter, il y a quelquefois des pb, même avec des codes corrects. Pour savoir si le code est ok, il suffit de le lancer à partir d'une console, ou d'un autre outil de développement. Chez moi (j'utilise eclipse), ton code fonctionne.

    Citation Envoyé par calogerogigante Voir le message
    quelle est la nature profonde de thread.start() : est-ce que cela veut dire qu'un thread ne démarre jamais QU'UNE SEULE FOIS ?
    Le code de la méthode run est la seule partie qui s'exécute en tâche de fond. elle démarre par l'appel start() et se termine par la terminaison normale de la méthode run().

    Il n'y a pas de raison de lancer un thread déjà en exécution. Si on veut lancer plusieurs threads identiques, on ajoute des instances de la classe héritée de thread, et on les lance chacune séparément.

    Bien entendu, une fois qu'un thread est arrêté, on peut le relancer si c'est utile! On peut aussi le laisser en exécution et le faire travailler sur évènement.

    Citation Envoyé par calogerogigante Voir le message
    quelle est la nature de thread.stop() : est-ce que cela veut dire qu'un THREAD s'arrête définitivement ?
    Il y a aucun moyen fourni d'arrêter un thread. La solution que tu as utilisée est l'une des astuces connues. Elle conduit à arrêter sur demande la boucle dans run(), ce qui termine run(), et donc ce qui arrête le thread.

    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

  6. #6
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Merci pour ta réponse très complète, Tyrtamos...

    J'ai encore des soucis : je suis sous Windows Vista et Windows 7, j'ai des tas d'erreurs (parfois oui, parfois non) avec mon code suivant, qui ne fonctionne pas : je n'arrive pas à faire démarrer les Threads indépendamment les un des autres... Est-ce que les threads de Python ont des soucis avec Vista ou Seven ? Ou alors je les utilise mal ?

    Voici le code sur lequel j'ai avancé :

    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
    #!/usr/local/bin/python
    # -*- coding:utf-8 -*-
    from Tkinter import *
    import threading
    import time
    from math import *
     
    class ObjetTournant(threading.Thread):
        def __init__(self, x, y, dans_canvas, ray, couleur):
            threading.Thread.__init__(self)
            self.rayon = ray
            self.x0 = x
            self.y0 = y
            self.coul = couleur
            self.angle = 0
            self.c = dans_canvas
            self.Fini = False
            self.ref = self.c.create_line(self.x0, self.y0, self.x0+self.rayon, self.y0, width = 8, fill=self.coul)
     
        def run(self):
            while not self.Fini:
                new_x = self.x0 + int(self.rayon * sin (radians(self.angle)))
                new_y = self.y0 + int(self.rayon * cos (radians(self.angle)))
                self.c.coords(self.ref, self.x0, self.y0, int(new_x), int(new_y))
                self.angle += 1
                if self.angle >= 360:
                    self.angle = 0
                time.sleep(0.01)
            print "Le thread ",self.coul," est fini."
     
        def stop(self):
            self.Fini = True
     
    class Application:
        def __init__(self):
            self.root=Tk()
            self.root.title('Objets tournants avec threads - v02')
            self.root.geometry('700x400')
            self.root.protocol("WM_DELETE_WINDOW", self.finirapplication)
     
            self.ca = Canvas(self.root, bg="white")
            self.ca.pack(side=LEFT, expand=YES, fill=BOTH)
     
            self.listeDesObjetsTournant = []
     
            self.listeDesObjetsTournant.append(ObjetTournant(100,200,self.ca, 50, "red"))
            self.listeDesObjetsTournant.append(ObjetTournant(500,100,self.ca, 30, "green"))
            self.listeDesObjetsTournant.append(ObjetTournant(340,200,self.ca, 40, "blue"))
            self.listeDesObjetsTournant.append(ObjetTournant(200,100,self.ca, 80, "black"))
     
            self.fra = Frame(self.root)
     
            t = 0
            for i in self.listeDesObjetsTournant:
                but1 = Button(self.fra, text="Start "+str(t), command=lambda m=i:self.objetdemarrer(m))
                but1.grid(row=t,column=0)
                but2 = Button(self.fra, text="Stop "+str(t), command=lambda m=i:self.objetstop(m))
                but2.grid(row=t,column=1)
                t += 1
     
            self.fra.pack(side=RIGHT)
     
            self.root.mainloop()
     
        def finirapplication(self):
            for obj in self.listeDesObjetsTournant:
                #obj.Fini = True
                obj.stop()
            sys.exit()
     
        def objetdemarrer(self, m):
            m.Fini = False
            m.start()
     
        def objetstop(self, m):
            m.stop()
     
    if __name__ == "__main__":
        app = Application()
    Message d'erreur fréquent :

    Exception in thread Thread-3:
    Traceback (most recent call last):
    File "C:\Python26\lib\threading.py", line 525, in __bootstrap_inner
    self.run()
    File "C:\PythonScripts\threads\objets_tournants_v02.py", line 24, in run
    self.c.coords(self.ref, self.x0, self.y0, int(new_x), int(new_y))
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 2136, in coords
    self.tk.call((self._w, 'coords') + args)))
    ValueError: invalid literal for float(): None
    Comment arriver à faire quelquechose de beau et de propre, qui ne plante pas, pour visualiser concrètement mes threads par des objets tournants sur un canvas, que je puis démarrer et stopper à ma guise...

    Difficle, les threads... Difficile...

    EDIT : les problèmes de plantage de Tkinter et de ses threads semblent connus :
    http://mail.python.org/pipermail/pyt...ne/023465.html

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

    Je viens de (re)découvrir qu'il ne faut pas relancer un thread qui a déjà été activé et arrêté (c'est dans la notice). J'étais pourtant persuadé que je l'avais déjà fait.

    Il est assez facile de prendre ça en compte: il suffit que le bouton qui lance le thread numéro k passe avec lambda l'indice k de self.listeDesObjetsTournant (et non pas l'objet lui-même) afin de recréer une nouvelle instance. En même temps, il faut lui passer les infos du thread précédent (d'indice k) afin que le rayon redémarre à partir de l'endroit précédent.

    Pour le reste des erreurs: je n'ai plus le tps aujourd'hui. Je regarderai demain si quelqu'un d'autre n'a pas déjà répondu.

    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

  8. #8
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Je suis toujours dans les patates avec la compréhension des Threads...

    Tant de fonctions qui ont l'air intéressantes :

    http://docs.python.org/library/threading.html

    et si peu d'exemples pour comprendre comment les utiliser correctement...

  9. #9
    Membre confirmé
    Avatar de vincent.mbg
    Homme Profil pro
    Développeur Python
    Inscrit en
    Décembre 2007
    Messages
    327
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Python

    Informations forums :
    Inscription : Décembre 2007
    Messages : 327
    Points : 618
    Points
    618
    Par défaut
    Bonjour,

    Le volume 2 de "Au cœur de python 2.5" Il explique tous les mécanismes et ne doit plus être très chère avec la sortie de python 2.7 et 3000.

    sinon sur ce site tu as apprendre a programmer avec python. Où il te montre comment optimiser des animation Tkinter avec les Thread par contre c'est pas très stable
    Mon guide pour apprendre Tkinter - N'oubliez pas de consulter les FAQ Python ou de visiter mon blog

  10. #10
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Citation Envoyé par vincent.mbg Voir le message
    Le volume 2 de "Au cœur de python 2.5" Il explique tous les mécanismes et ne doit plus être très chère avec la sortie de python 2.7 et 3000.
    Merci Vincent. Je n'ai malheureusement jamais vu ce livre en kiosque (le volume 1 oui, mais pas le 2...).

    Je vais donc essayer de le feuilleter quelque part et peut-être l'acheter alors, s'il est bien fait...

    Est-ce que les Threads déstabilisent d'office Python dès qu'ils sont utilisés avec Tkinter ?

    Si c'est le cas, c'est pas top, la vie, moi qui m'investit à fond dans Tkinter pour l'instant !

  11. #11
    Membre confirmé
    Avatar de vincent.mbg
    Homme Profil pro
    Développeur Python
    Inscrit en
    Décembre 2007
    Messages
    327
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Python

    Informations forums :
    Inscription : Décembre 2007
    Messages : 327
    Points : 618
    Points
    618
    Par défaut
    Euh , je sais pas si Tkinter et Thread c'est deux choses compatibles...

    J'avais essayé de faire un clone de fantastique contraption

    mais je me suis très vite confronté a des plantages étranges,

    Ca plantait jamais au même moment pour une même situation, j'ai remarqué qu'il plantait beaucoup plus vite sur des corp2duo.

    Je joins le fichier si quelqu'un veux expérimenter l'instabilité

    Il y a quelque chose à savoir, Python ne gère que des processus légers ou Thread cela est dit au GIL (Global interpreteur Lock) Python ne pouvant contrôler qu'un seul thread dans sa boucle principale, un système de verrou (GIL) a été mit en place.

    Je crois que le module multiprocessing de python 2.6 à permit de surmonter le problème du GIL en permettant d'utiliser processus lours (programme partagé sur plusieurs cpu )

    Après il y a des modules associés aux Thread comme queue permettant de faire des files d'attente pour la communication interThread.

    Voila ce dont je me souviens...

    Tu devrais regarder dans les sources de python, c'est plein d'exemple ( répertoire DEMO après décompression )
    Fichiers attachés Fichiers attachés
    Mon guide pour apprendre Tkinter - N'oubliez pas de consulter les FAQ Python ou de visiter mon blog

  12. #12
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Citation Envoyé par vincent.mbg Voir le message
    Tu devrais regarder dans les sources de python, c'est plein d'exemple ( répertoire DEMO après décompression )
    Quel excellent conseil : c'est en effet pleins de petits scripts intéressants.

    Concernant le threading et Tkinter, j'ai déjà remarqué ce 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
    50
    # Brownian motion -- an example of a multi-threaded Tkinter program.
     
    from Tkinter import *
    import random
    import threading
    import time
    import sys
     
    WIDTH = 400
    HEIGHT = 300
    SIGMA = 10
    BUZZ = 2
    RADIUS = 2
    LAMBDA = 10
    FILL = 'red'
     
    stop = 0                                # Set when main loop exits
     
    def particle(canvas):
        r = RADIUS
        x = random.gauss(WIDTH/2.0, SIGMA)
        y = random.gauss(HEIGHT/2.0, SIGMA)
        p = canvas.create_oval(x-r, y-r, x+r, y+r, fill=FILL)
        while not stop:
            dx = random.gauss(0, BUZZ)
            dy = random.gauss(0, BUZZ)
            dt = random.expovariate(LAMBDA)
            try:
                canvas.move(p, dx, dy)
            except TclError:
                break
            time.sleep(dt)
     
    def main():
        global stop
        root = Tk()
        canvas = Canvas(root, width=WIDTH, height=HEIGHT)
        canvas.pack(fill='both', expand=1)
        np = 30
        if sys.argv[1:]:
            np = int(sys.argv[1])
        for i in range(np):
            t = threading.Thread(target=particle, args=(canvas,))
            t.start()
        try:
            root.mainloop()
        finally:
            stop = 1
     
    main()
    On peut noter ceci : dans la boucle while répétée par chaque thread, l'opération de modification d'un objet Tkinter (le canvas) est malgré tout englobé dans un try catch :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            try:
                canvas.move(p, dx, dy)
            except TclError:
                break
    Trois questions me viennent à l'esprit :

    Est-ce un indice de l'instabilité de travailler dans Tkinter en utilisant des threads ?

    Et est-ce que ce petit truc de placer une opération de mise à jour d'un canvas dans un try catch permet de solutionner le couplage thread-tkinter ?

    TclError est-il un groupe d'erreurs liées à Tkinter ?

  13. #13
    Membre confirmé
    Avatar de vincent.mbg
    Homme Profil pro
    Développeur Python
    Inscrit en
    Décembre 2007
    Messages
    327
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Python

    Informations forums :
    Inscription : Décembre 2007
    Messages : 327
    Points : 618
    Points
    618
    Par défaut
    sympa comme script mais chez moi il plante

    Cette ligne n'es jamais exécuté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        p = canvas.create_oval(x-r, y-r, x+r, y+r, fill=FILL)
    TclError est-il un groupe d'erreurs liées à Tkinter ?
    Python embarque un schell tcl/tk qui s'occupe de l'affichage graphique. Tkinter est un interpréteur de Tk pour python ( TK INTERpreter) cette erreur est liée à Tk, c'est une erreur Tcl interprété pour Python.

    Tu peux directement dialogué avec le schell tcl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    >>> from Tkinter import *
    >>> root = Tk()
    >>> tcl = root.eval
    >>> tcl( "label .lab1 -text toto" ) # code tcl/tk.
    '.lab1'
    >>> tcl( "pack lab1" ) # oubli du point.
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    _tkinter.TclError: wrong # args: should be "pack option arg ?arg ...?" 
    >>> tcl( "pack .lab1" )
    ''
    >>>
    Si tu laisse tourner longtemps ce programme une erreur est t-elle affichée ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    try:
        canvas.move(p, dx, dy)
    except TclError as e :
        print "error : ", e
        break
    Mon guide pour apprendre Tkinter - N'oubliez pas de consulter les FAQ Python ou de visiter mon blog

  14. #14
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Que je lance le script du mouvement brownien par une fenêtre DOS ou par IDLE (je suis sous Windows 7, python 2.6.4.), tout tourne très bien, sans message d'erreur, même pendant longtemps (10 min)...

    Quand je clos le programme, j'ai un plantage de Python quand le script du mouvement brownien a été lancé via IDLE...

    P.S. : Merci pour ton info sur le shell Tcl/Tk, très intéressant...

  15. #15
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Voici le genre d'application où je voulais arriver avec Tkinter : visualiser graphiquement (avec Tkinter) l'activité des threads...



    Et voici 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
    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
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    #!/usr/local/bin/python
    # -*- coding:utf-8 -*-
    from Tkinter import *
    import threading
    import time
    from math import *
     
    class ObjetTournant(threading.Thread):
        def __init__(self, x, y, dans_canvas, ray, couleur, nom):
            threading.Thread.__init__(self)
            self.rayon = ray
            self.x0 = x
            self.y0 = y
            self.coul = couleur
            self.name = nom
            self.angle = 0
            self.c = dans_canvas
            self.Fini = False
            self.pause = False
            self.reference = self.c.create_line(self.x0, self.y0, self.x0, self.y0+self.rayon, width = 8, fill=self.coul)
            print "Initial :",self.c,"\n"
     
        def run(self):
            while not self.Fini:
                if self.pause == False:
                    try:
                        new_x = self.x0 + self.rayon * sin (radians(self.angle))
                        new_y = self.y0 + self.rayon * cos (radians(self.angle))
                        print "Run : ",self.name,"\n"
                        self.c.coords(self.reference, self.x0, self.y0, int(new_x), int(new_y))
                        self.angle += 1
                        if self.angle >= 360:
                            self.angle = 0
                    except TclError:
                        break
                time.sleep(0.01)
            print "Le thread ",self.name," est fini.\n"
     
        def arretetoi(self):
            self.Fini = True
     
    class Application:
        def __init__(self):
            self.root=Tk()
            self.root.title('Objets tournants avec threads - v04')
            self.root.geometry('700x200')
            self.root.protocol("WM_DELETE_WINDOW", self.finirapplication)
     
            self.ca = Canvas(self.root, bg="white")
            self.ca.pack(side=LEFT, expand=YES, fill=BOTH)
     
            self.fra = Frame(self.root)
     
            self.but_1_1 = Button(self.fra, text="Start 1",   command=self.objet1demarrer)
            self.but_1_1.grid(row=0,column=0)
            self.but_1_2 = Button(self.fra, text="Pause 1",   state=DISABLED, command=self.objet1pause)
            self.but_1_2.grid(row=0,column=1)
            self.but_1_3 = Button(self.fra, text="Reprise 1", state=DISABLED, command=self.objet1pause)
            self.but_1_3.grid(row=0,column=2)
            self.but_1_4 = Button(self.fra, text="Stop 1",    state=DISABLED, command=self.objet1stop)
            self.but_1_4.grid(row=0,column=3)
     
            self.but_2_1 = Button(self.fra, text="Start 2",   command=self.objet2demarrer)
            self.but_2_1.grid(row=1,column=0)
            self.but_2_2 = Button(self.fra, text="Pause 2",   state=DISABLED, command=self.objet2pause)
            self.but_2_2.grid(row=1,column=1)
            self.but_2_3 = Button(self.fra, text="Reprise 2", state=DISABLED, command=self.objet2pause)
            self.but_2_3.grid(row=1,column=2)
            self.but_2_4 = Button(self.fra, text="Stop 2",    state=DISABLED, command=self.objet2stop)
            self.but_2_4.grid(row=1,column=3)
     
            self.but_3_1 = Button(self.fra, text="Start 3",   command=self.objet3demarrer)
            self.but_3_1.grid(row=2,column=0)
            self.but_3_2 = Button(self.fra, text="Pause 3",   state=DISABLED, command=self.objet3pause)
            self.but_3_2.grid(row=2,column=1)
            self.but_3_3 = Button(self.fra, text="Reprise 3", state=DISABLED, command=self.objet3pause)
            self.but_3_3.grid(row=2,column=2)
            self.but_3_4 = Button(self.fra, text="Stop 3",    state=DISABLED, command=self.objet3stop)
            self.but_3_4.grid(row=2,column=3)
     
            self.but_4_1 = Button(self.fra, text="Start 4",   command=self.objet4demarrer)
            self.but_4_1.grid(row=3,column=0)
            self.but_4_2 = Button(self.fra, text="Pause 4",   state=DISABLED, command=self.objet4pause)
            self.but_4_2.grid(row=3,column=1)
            self.but_4_3 = Button(self.fra, text="Reprise 4", state=DISABLED, command=self.objet4pause)
            self.but_4_3.grid(row=3,column=2)
            self.but_4_4 = Button(self.fra, text="Stop 4",    state=DISABLED, command=self.objet4stop)
            self.but_4_4.grid(row=3,column=3)
     
            self.fra.pack(side=RIGHT)
     
            self.obj1 = ObjetTournant( 60,100,self.ca, 50, "red",  "1")
            self.obj2 = ObjetTournant(200,100,self.ca, 30, "green","2")
            self.obj3 = ObjetTournant(300,100,self.ca, 40, "blue", "3")
            self.obj4 = ObjetTournant(400,100,self.ca, 80, "black","4")
     
            self.root.mainloop()
     
        def finirapplication(self):
            self.obj1.arretetoi()
            sys.exit()
     
        # ============================================================
     
        def objet1demarrer(self):
            print "On demarre le thread 1\n"
            self.obj1.start()
            self.but_1_1.config(state=DISABLED)
            self.but_1_2.config(state=NORMAL)
            self.but_1_4.config(state=NORMAL)
     
        def objet1stop(self):
            print "On doit stopper le thread 1\n"
            self.obj1.arretetoi()
            self.but_1_1.config(state=DISABLED)
            self.but_1_2.config(state=DISABLED)
            self.but_1_3.config(state=DISABLED)
            self.but_1_4.config(state=DISABLED)
     
        def objet1pause(self):
            if self.obj1.pause == False:
                print "On met le thread 1 en pause\n"
                self.but_1_2.config(state=DISABLED)
                self.but_1_3.config(state=NORMAL)
                self.obj1.pause = True
            else:
                print "On reprend le thread 1 qui etait en pause\n"
                self.but_1_2.config(state=NORMAL)
                self.but_1_3.config(state=DISABLED)
                self.obj1.pause = False
     
        # ============================================================
     
        def objet2demarrer(self):
            print "On demarre le thread 2\n"
            self.obj2.start()
            self.but_2_1.config(state=DISABLED)
            self.but_2_2.config(state=NORMAL)
            self.but_2_4.config(state=NORMAL)
     
        def objet2stop(self):
            print "On doit stopper le thread 2\n"
            self.obj2.arretetoi()
            self.but_2_1.config(state=DISABLED)
            self.but_2_2.config(state=DISABLED)
            self.but_2_3.config(state=DISABLED)
            self.but_2_4.config(state=DISABLED)
     
        def objet2pause(self):
            if self.obj2.pause == False:
                print "On met le thread 2 en pause\n"
                self.but_2_2.config(state=DISABLED)
                self.but_2_3.config(state=NORMAL)
                self.obj2.pause = True
            else:
                print "On reprend le thread 2 qui etait en pause\n"
                self.but_2_2.config(state=NORMAL)
                self.but_2_3.config(state=DISABLED)
                self.obj2.pause = False
     
        # ============================================================
     
        def objet3demarrer(self):
            print "On demarre le thread 3\n"
            self.obj3.start()
            self.but_3_1.config(state=DISABLED)
            self.but_3_2.config(state=NORMAL)
            self.but_3_4.config(state=NORMAL)
     
        def objet3stop(self):
            print "On doit stopper le thread 3\n"
            self.obj3.arretetoi()
            self.but_3_1.config(state=DISABLED)
            self.but_3_2.config(state=DISABLED)
            self.but_3_3.config(state=DISABLED)
            self.but_3_4.config(state=DISABLED)
     
        def objet3pause(self):
            if self.obj3.pause == False:
                print "On met le thread 3 en pause\n"
                self.but_3_2.config(state=DISABLED)
                self.but_3_3.config(state=NORMAL)
                self.obj3.pause = True
            else:
                print "On reprend le thread 3 qui etait en pause\n"
                self.but_3_2.config(state=NORMAL)
                self.but_3_3.config(state=DISABLED)
                self.obj3.pause = False
     
        # ============================================================
     
        def objet4demarrer(self):
            print "On demarre le thread 4\n"
            self.obj4.start()
            self.but_4_1.config(state=DISABLED)
            self.but_4_2.config(state=NORMAL)
            self.but_4_4.config(state=NORMAL)
     
        def objet4stop(self):
            print "On doit stopper le thread 4\n"
            self.obj4.arretetoi()
            self.but_4_1.config(state=DISABLED)
            self.but_4_2.config(state=DISABLED)
            self.but_4_3.config(state=DISABLED)
            self.but_4_4.config(state=DISABLED)
     
        def objet4pause(self):
            if self.obj4.pause == False:
                print "On met le thread 4 en pause\n"
                self.but_4_2.config(state=DISABLED)
                self.but_4_3.config(state=NORMAL)
                self.obj4.pause = True
            else:
                print "On reprend le thread 4 qui etait en pause\n"
                self.but_4_2.config(state=NORMAL)
                self.but_4_3.config(state=DISABLED)
                self.obj4.pause = False
     
    if __name__ == "__main__":
        app = Application()
    Cela semble fonctionner sans plantage... Est-ce grâce au try/catch avec TclError ?

    Est-ce la bonne façon de faire des threads couplés à des objets de Tkinter ?

    Je ne sais pas... La question reste posée...

  16. #16
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    De mon coté cd code cela plante aléatoirement (pas de reprise, plantage de python.exe) et ce avec ou sans try.

    python 2.6/3 sous vista

    @+
    Merci d'utiliser le forum pour les questions techniques.

  17. #17
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Ce que j'aimerais savoir : est-ce que les plantages que nous rencontrons tous sont dû à :

    - Tkinter ?
    - Tkinter couplé aux threads ?
    - Aux threads seuls (dans ce cas, ça se saurait si Python n'était pas performant de ce point de vue là, non) ?

    Les gens qui utilisent les threads avec wxPython ont-ils moins de plantage quand ils travaillent avec des threads ? (je ne connais pas bien encore wxPython pour pouvoir faire des petits tests...)

    Toutes des questions qui restent ouvertes, et qui font que je vais laisser de côté de nouveau les Threads, pour l'instant...

  18. #18
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    D'après les logs cela ressemble plus à un plantage tk (positionnement du widget).
    Ceci dit cela le fait après plusieurs pauses/reprises.
    Je testerais cela ce soir.
    Merci d'utiliser le forum pour les questions techniques.

  19. #19
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Ton code fonctionne très bien sous Linux. Ton problème semble donc venir de Tkinter(Tk)/Windows (Je pense à la dll Tcl).

    Cela semble confirmé par

    Citation Envoyé par calogerogigante Voir le message
    But : essayer d'en voir plusieurs en fonctionnement simultané. Voici ce que cela donne (attention, ça plante dans IDLE, je sais pas trop pourquoi ?) :

    - est-ce que ce code ci-dessus est correct ? (parce qu'il plante souvent mon IDLE, et même parfois l'exécutable python lui-même, carrément !)
    IDLE c'est du Tkinter non ?

    @+
    Merci d'utiliser le forum pour les questions techniques.

  20. #20
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Ce que tu dis confirme ma décision : puisqu'il y a tant de problèmes avec les threads qui font planter Python sous Windows quand on utilise Tkinter, je reviendrais alors plus tard vers mon étude des threads (que j'aime bien visualiser graphiquement) quand je me mettrais sérieusement à wxPython, dans quelques mois...

Discussions similaires

  1. [PHP 5.0] Mon sujet pour comprendre la POO avec PHP
    Par Le nettoyeur dans le forum Langage
    Réponses: 3
    Dernier message: 09/07/2014, 18h05
  2. Trouver infos pour une liste dans une base de donnees
    Par clairejp dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 29/07/2011, 18h26
  3. 5 minutes pour comprendre le développement avec Kinect
    Par Gordon Fowler dans le forum Débuter
    Réponses: 10
    Dernier message: 07/07/2011, 11h18
  4. [Info] Nouvel Ubuntu 11.04 avec Python 2.7.1
    Par tyrtamos dans le forum Général Python
    Réponses: 11
    Dernier message: 04/05/2011, 10h48
  5. cmt se connecté a oracle pour faire une requete avec python
    Par dipajero dans le forum Bibliothèques tierces
    Réponses: 6
    Dernier message: 28/12/2005, 20h22

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