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

PyQt Python Discussion :

Structure programme Thread


Sujet :

PyQt Python

  1. #1
    Membre régulier
    Homme Profil pro
    Ingénieur développement de composants
    Inscrit en
    Décembre 2019
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement de composants

    Informations forums :
    Inscription : Décembre 2019
    Messages : 113
    Points : 72
    Points
    72
    Par défaut Structure programme Thread
    Bonjour,
    je m'interroge sur la pertinence de la structure d'un programme que je viens de créer (voir ci dessous).

    De ma vision, il "fonctionne" mais j'ai un peu galéré à le faire fonctionner...
    Je me demande si la structure et l'organisation des objets entre eux sont correctement gérés.
    l'objectif est de faire un graphique live de différentes courbes avec du traitement/analyse en temps réel.

    j'ai préféré pyqtgraph à matplotlib en grande partie pour sa "réactivité" (matplotlib est plus joli mais la gestion des tracés live est moins dynamique je trouve... ).
    Pour être fluide j'ai basculé la partie analyse/tracé/récupération des datas dans un thread... lui même actionné en boucle sur un QTimer.
    l'objectif est de pouvoir faire tourner la chose en ayant la main sur l'ordi pour faire autre chose en même temps...

    est-ce que le prog est OK ou maladroit? la gestion du Thread/Timer? la manière dont le thread est arrêtée?

    merci pour vos avis :-)


    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
    from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton
    from PyQt5.QtCore import QTimer, QThread, QEventLoop, QThread
    import pyqtgraph as pg
    import sys
    import time
    import math
    import numpy as np
     
     
    class test(QThread):
        def __init__(self, ui):
            QThread.__init__(self)
            print("Thread initialisé")
            self.ui=ui
            self.i = 0
            self.x=[]
            self.y=[]
            self.y2=[]
            self.y3=[]
            self.data_Timer = QTimer()
            self.data_Timer.moveToThread(self)
            self.data_Timer.timeout.connect(self.collect_Data)
     
        def run(self):
            print("Thread lancé!")
            self.data_Timer.start(250)
            loop = QEventLoop()
            loop.exec_()
     
        def collect_Data(self):
            self.i = self.i + 1
            self.x.append(self.i)
            self.y.append(math.cos(self.i))
            self.y2.append(math.sin(self.i))
            if math.cos(self.i) > 0.75:
                self.y3.append(math.cos(self.i))
            else:
                self.y3.append(np.nan)
            self.ui.graphique_1.setData(self.x, self.y)
            self.ui.graphique_2.setData(self.x, self.y2)
            self.ui.graphique_3.setData(self.x, self.y3)
     
        def stop(self):
            self.quit()
            print("thread stoppé")
     
     
    class MainWindow(QMainWindow):
        def __init__(self):
            QMainWindow.__init__(self)
     
            self.fenetre_widget = QWidget()
     
            self.graphique_live = pg.GraphicsWindow()
            self.plot1 = self.graphique_live.addPlot(0, 0, title="azerty")
            self.graphique_1 = self.plot1.plot([], [], pen=pg.mkPen('w', width=1))
            self.graphique_2 = self.plot1.plot([], [], pen=pg.mkPen('g', width=1))
            self.graphique_3 = self.plot1.plot([], [], pen=None, symbol='o', symbolBrush =(0, 255, 255), symbolSize = 14, symbolPen ='w', connect="finite")
            self.bouton_go = QPushButton("GO")
            self.bouton_stop = QPushButton("Stop")
     
            layout_vertical = QVBoxLayout()
            layout_vertical.addWidget(self.graphique_live)
            layout_vertical.addWidget(self.bouton_go)
            layout_vertical.addWidget(self.bouton_stop)
     
            self.thread_get_data = test(self)
            self.bouton_go.clicked.connect(self.tracer)
            self.bouton_stop.clicked.connect(self.stop)
     
            self.fenetre_widget.setLayout(layout_vertical)
            self.setCentralWidget(self.fenetre_widget)
     
        def stop(self):
            self.thread_get_data.stop()
     
        def tracer(self): 
            self.thread_get_data.start()
     
     
    if __name__ == "__main__":
        appli = QApplication(sys.argv)
        fenetre_main = MainWindow()
        fenetre_main.show()
        sys.exit(appli.exec_())

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Pourquoi un thread pour faire juste faire péter un timer toutes les x ms?

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

  3. #3
    Membre régulier
    Homme Profil pro
    Ingénieur développement de composants
    Inscrit en
    Décembre 2019
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement de composants

    Informations forums :
    Inscription : Décembre 2019
    Messages : 113
    Points : 72
    Points
    72
    Par défaut
    Bonjour,
    et bien dans l'exemple donné ici, c'est vrai, le thread peut paraitre accessoire parce que la fonction contenu dans le thread est très légère.
    dans mon application réelle, le calcul mathématique que l'ordi doit faire me demande entre 4 et 10 secondes de traitement...
    du coup, j'avais envie de basculer ce traitement dans un thread histoire de ne pas tout me figer à chaque fois que l'ordi récupère un flot de data...

    et le timer me sert à justement analyser la data régulièrement.

    et je n'attend pas que la data s'accumule parce que c'est pour un asservissement qui demande un résultat dans le présent... pas une fois que les évènement sont passée.

    j'envisage de faire en sorte que le timer soit quoi qu'il arrive > au temps de traitement du thread... mais bon je ne suis pas certain de m'y prendre correctement.. peut être qu'il y a un autre moyen?

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Pas sûr d'avoir tout compris mais le thread remplit un tableau à son rythme, le timer va mettre à jour l'affichage avec un sous ensemble du tableau.

    Il serait préférable d'avoir timer et côté graphique dans le même thread (la principale) et le thread qui mouline dans son coin.

    La vrai question est plutôt sur la structure de données à placer entre les deux et comment en synchroniser l'accès.

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

  5. #5
    Membre régulier
    Homme Profil pro
    Ingénieur développement de composants
    Inscrit en
    Décembre 2019
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement de composants

    Informations forums :
    Inscription : Décembre 2019
    Messages : 113
    Points : 72
    Points
    72
    Par défaut
    je pensais que le QTHread était simplement un moyen de basculer une opération en tache de fond. ce qui permet de maintenir l’interaction possible entre l'IHM (le graphique avec ses fonctions) et l'analyse en cours.

    le timer est, je pense, uniquement là pour rafraichir régulièrement l'analyse affichée. A lui seul, je pense que je me retrouverais dans une situation où à chaque execution de la tache qui lui est associée, j'aurais droit à un sablier me bloquant l'ordi pendant toute son execution... ce qui serait embetant.

    j'imaginais que le fait d'inclure le QTimer dans le QThread était une approche permettant de rendre "transparente" l'analyse de fond du graphique et de sa data. Alors certes, il y a un décalage relatif à l'exection du thread lui même mais à tout instant je peux réduire l'IHM et faire autre chose. à tout instant je peut ré-afficher l'IHM en ayant à l'affichage de la version la plus récente possible de l'ensemble de l'analyse sans avoir à cliquer sur quelque chose pour "updater" quelque chose.

    en gros imaginer un calcul qui demande 1 semaine pleine. mais que ce calcul puisse être coupé en sous-éléments indépendant ne représentant que 10 secondes de calcul. autant avoir les premiers résultats dès que possible pour stopper l'analyse au besoin. et autant que tout se déroule "au plus tôt" sans avoir à charger les dernier éléments manuellement...

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,

    Vous ne devez pas penser mais lire la documentation de .setData pour savoir s'il s'agit d'un slot (appelable depuis un autre thread) ou d'une simple méthode(devant être appelée dans le même thread que le GUI).

    Pour infos thread et GUI coexistent assez mal.
    Qt a fait un boulot magnifique pour simplifier la vie des développeurs C++ en leur évitant d'avoir à réaliser des changements de contexte et des "cast" de structures "à la main" (lorsqu'on passe une fonction en paramètre).

    Mais çà ne marche pas tout seul... et vous devez avoir une idée des problèmes sous jacents qu'on a cherché à résoudre pour ne pas faire n'importe quoi.

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

  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,

    S'il s'agit de placer des calculs longs dans un thread pour éviter de geler le graphique, c'est ok! Mais le thread ne doit pas toucher directement au graphique (celui-ci n'est pas "thread-safe"). Au fur et à mesure que des données sont disponibles, le thread les envoie au graphique par des messages (.emit), et les infos correspondantes sont reçues par une des méthodes du graphique tel que prévu (.connect). C'est comme ça, par exemple, qu'on met à jour une barre de progression en fonction de la progression d'un calcul ou d'une opération longue (téléchargement, ...) d'un thread.

    La classe QThread est intéressante parce que, justement, elle sait émettre de tels messages. On peut obtenir la même chose avec threading, mais il faut créer une classe avec un héritage multiple threading + QObject.
    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 régulier
    Homme Profil pro
    Ingénieur développement de composants
    Inscrit en
    Décembre 2019
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement de composants

    Informations forums :
    Inscription : Décembre 2019
    Messages : 113
    Points : 72
    Points
    72
    Par défaut
    super,
    merci pour ces précisions et conseils :-)
    je n'avais pas connaissances de ces nuances et je sais maintenant sur quels aspects de la documentation me pencher!

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/05/2015, 00h01
  2. Structure programme MVC
    Par RomG7 dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 20/07/2012, 15h12
  3. [optimisation d'un programme] Thread et mode serveur
    Par Battant dans le forum Général Java
    Réponses: 0
    Dernier message: 19/03/2010, 00h46
  4. Aval structure GUI + Threads
    Par N.tox dans le forum Général Python
    Réponses: 1
    Dernier message: 25/02/2010, 15h19
  5. Envoie de structure à un thread.
    Par mohdaef dans le forum Threads & Processus
    Réponses: 2
    Dernier message: 24/03/2008, 17h23

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