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 :

[PEP][Architecture][Thread] Bonnes pratiques [Python 3.X]


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 12
    Par défaut [PEP][Architecture][Thread] Bonnes pratiques
    Bonjour à tous.

    1 / Le contexte
    Après une première vie professionnelle d'analyste programmeur (C#, php, SQL, Jquerry/javascript) et une pause de 5 ans je me remets à la programmation en apprenant le Python suite à l’acquisition d'un raspberry et de composants électroniques. Comme premier exercice de remise en route j'ai donc branché les composants suivant sur mon raspberry ; capteur de pression et de température, capteur d'humidité, petit écran LCD, LED red green blue ainsi que deux bouton physiques. Lors de l'appuie sur le bouton_1 j'allume ma LED et lui fait changer de couleurs selon un tableau descripteur que je fournis à ma classe LED, un deuxième appuie éteint la LED. En appuyant sur le bouton_2 je récupère pression température et taux d'humidité de mes composants et j'affiche tout ça sur le petit écran LCD agrémenté de la date et de l'heure, un deuxième appuie force un refresh de ces infos.

    2/ Mon problème
    Je me rends compte que j'ai très mal géré mes Threads.
    En effet j'ai du en utiliser car la boucle d'affichage de ma LED ou l'affichage de la météo bloquait le reste de l'exécution de mon programme, logique.
    Jusque ici j'ai réussi à lancer l'exécution de ses bouts de code dans des Thread et mon programme ne se bloque donc plus sur l'exécution d'une tache.
    Cependant je n'arrive pas à les fermer proprement, si j'appuie plusieurs fois sur le bouton contrôlant ma LED j'ai plusieurs Thread qui tournent en concurrence, ce n'est pas ce que je veux.
    Je crois comprendre que je dois hériter la classe threading.Thread afin de coder proprement un événement stop.
    Aimant développer selon les standards et selon une architecture propre je me tourne vers vous car je trouve étrange que ma classe LED hérite de threading.Thread.

    3/ Un peu de code
    Je ne vous montre que ce qui me semble nécessaire à la résolution de mon problème tout en y ajoutant quelques commentaires pour votre compréhension.
    Je sais bien qu'il y a des bouts de codes pas logiques/inutile/mal placés mais comme je vous l'ai dit je développe tout en apprenant et je remanie au fur et à mesure.

    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
     
    class Led:
        def __init__(self, redpin, greenpin, bluepin, delay, freq, blink_seq):
     
            print("object led constructor")
            self.redPin = redpin
            self.greenPin = greenpin
            self.bluePin = bluepin
            self.delay = delay
            self.freq = freq
            self.blinkSeq = blink_seq
     
            # fixe attributs
            self.redValue = 99
            self.greenValue = 0
            self.blueValue = 33
            self.blinkStatut = False
            self.blinkMod = "none"
     
            GPIO.setup(self.redPin, GPIO.OUT)
            GPIO.setup(self.greenPin, GPIO.OUT)
            GPIO.setup(self.bluePin, GPIO.OUT)
     
            self.redPWM = GPIO.PWM(self.redPin, self.freq)
            self.greenPWM = GPIO.PWM(self.greenPin, self.freq)
            self.bluePWM = GPIO.PWM(self.bluePin, self.freq)
            self.turn_on()
            self.set_color([self.redValue, self.greenValue, self.blueValue])
     
        def blink(self):
            # TODO ne plus commencer le blinkMod = cycle par la couleur rouge mais n'importe laquelle
            print('BLINK')
            if self.blinkStatut:
                self.turn_off()
                self.blinkStatut = False
            else:
                self.turn_on()
                self.blinkStatut = True
                self.redValue = 100  # on initie la LED a rouge pour le cas general
                i = 0
                while self.blinkStatut:
                    if type(self.blinkSeq[i]) is int:
                        if self.blinkMod == "color":
                            # apres des sequence en mode couleur on repart de rouge
                            self.redValue = 100
                            self.greenValue = 0
                            self.blueValue = 0
                            self.blinkMod = "cycle"
                        delay = self.delay
                        if self.redValue > 0 and self.blueValue == 0:
                            self.redValue -= self.blinkSeq[i]
                            self.greenValue += self.blinkSeq[i]
                        elif self.greenValue > 0 and self.redValue == 0:
                            self.greenValue -= self.blinkSeq[i]
                            self.blueValue += self.blinkSeq[i]
                        elif self.blueValue > 0 and self.greenValue == 0:
                            self.blueValue -= self.blinkSeq[i]
                            self.redValue += self.blinkSeq[i]
                            if self.blueValue <= 0:
                                i += 1
                            if i > len(self.blinkSeq) - 1:
                                i = 0
     
                        if self.redValue < 0:
                            self.redValue = 0
                        if self.redValue > 100:
                            self.redValue = 100
                        if self.greenValue < 0:
                            self.greenValue = 0
                        if self.greenValue > 100:
                            self.greenValue = 100
                        if self.blueValue < 0:
                            self.blueValue = 0
                        if self.blueValue > 100:
                            self.blueValue = 100
     
                    else:
                        self.blinkMod = "color"
                        delay = float(self.blinkSeq[i].split(':')[1])
                        self.redValue = int(self.blinkSeq[i].split(':')[0].split("-")[0])
                        self.greenValue = int(self.blinkSeq[i].split(':')[0].split("-")[1])
                        self.blueValue = int(self.blinkSeq[i].split(':')[0].split("-")[2])
                        i += 1
                        if i > len(self.blinkSeq) - 1:
                            i = 0
     
                    self.set_color([self.redValue, self.greenValue, self.blueValue])
                    time.sleep(delay)
     
     
    GPIO.setmode(GPIO.BCM)
    #ci dessous une liste qui sert à indiquer le cycle d'affichage que la LED doit suivre, les int correspondent à un temps pour le mode défilement de couleur, les strings à une couleurs et une durée précise
    modelBlink = [1, 5, 10, 10, 10, 20, 20, 20, 33, 33, 33,
                  "100-000-000:0.3", "000-100-000:0.3", "000-000-100:0.3",
                  "033-066-099:0.3", "99-66-33:0.3", "066-099-033:0.3", "033-099-066:0.3",
                  "100-050-000:0.3", "100-000-050:0.3", "000-100-050:0.3", "050-100-000:0.3", "000-050-100:0.3",
                  "050-000-100:0.3",
                  "005-000-000:0.3", "000-010-000:0.3", "000-000-020:0.3", "030-000-000:0.3", "000-040-000:0.3",
                  "000-000-050:0.3", "060-000-000:0.3",
                  "000-070-000:0.3", "000-000-080:0.3", "090-000-000:0.3", "000-100-000:0.3",
                  33, 33, 33, 20, 20, 20, 10, 10, 5, 1]
    led_1 = Led(17, 18, 27, 0.01, 100, modelBlink)
    myThreads = {}
     
     
    def button_callback1(channel):
     
        print("button_callback1")
     
        if "led" not in myThreads:
            myThreads["led"] = []
        th = threading.Thread(target=led_1.blink)
        th.start()
     
        #ci dessous tentative (malheureuse&inefficace) de fermeture des autres Thread relatifs à la LED
        #Les Threads ne sont pas supprimés de la liste par soucis de débogage
        for elt in myThreads["led"]:
            elt.join()
     
        myThreads["led"].append(th)
     
     
    def main():
        GPIO.setup(22, GPIO.IN, GPIO.PUD_UP)  # bouton 1
        GPIO.setup(24, GPIO.IN, GPIO.PUD_UP)  # bouton 2
        GPIO.add_event_detect(22, GPIO.RISING, button_callback1, bouncetime=500)
        GPIO.add_event_detect(24, GPIO.RISING, button_callback2, bouncetime=500)
        LCD1602.init(0x27, 1)  # init(slave address, background light)
        LCD1602.write(0, 0, '      GPIO      ')
        LCD1602.write(0, 1, '     ON AIR     ')
     
     
    try:
        main()
        input() # Moyen pas propre que j'ai trouvé pour que mon programme ne se referme pas tout de suite, une suggestion ?
    except (KeyboardInterrupt, SystemExit, SystemError):
        destroy()

    4/ Ma question
    Selon ce que j'ai lu je serait censé faire en sorte que ma classe LED hérite de la classe threading.Thread afin de pouvoir manipuler en marqueur Terminated ainsi que l'ajout d'un événement stop ?
    Est ce une bonne pratique ? Ne trouvez vous pas architecturalement parlant bancale le fait que ma classe LED hérite de threading.Thread ?
    J'ai intuitivement l'impression que ma classe LED n'est pas le bonne endroit du code ou exécuter la logique relative aux Thread.
    D'ailleurs on peut certainement imaginer un cas ou ma classe LED puisse être appelé dans un Thread à part ou dans le Thread principal, à ce moment là le fait de mettre la logique du Thread dans la classe serait bloquant.
    Qu'en pensez vous ?
    Je suis aussi preneur de tout autre conseil.
    Merci beaucoup d'avoir prit le temps de me lire jusque ici.

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

    Hériter de Thread ou passer en paramètre une fonction à appeler ont le même résultat: lorsque la méthode "run" du thread se termine, le thread est terminé. Pour vous en convaincre, vous pouvez écrire des petits bouts de code et vérifier.

    Après il y a:
    Cependant je n'arrive pas à les fermer proprement, si j'appuie plusieurs fois sur le bouton contrôlant ma LED j'ai plusieurs Thread qui tournent en concurrence, ce n'est pas ce que je veux.
    Si ce n'est pas ce que vous voulez, il faut "bloquer" le bouton en attendant que l'action déjà lancée se termine i.e. tester si le thread est encore vivant (via .is_alive()).

    Je crois comprendre que je dois hériter la classe threading.Thread afin de coder proprement un événement stop.
    Soit le thread se termine rapidement et un .join suffit... Soit c'est une activité répétitive qui ne s'arrêtera qu'en testant un drapeau/Event ou à la sortie du programme (si on a mis le flag deamon=True).
    note: et pour tester un flag, inutile d'hériter de Thread...

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

  3. #3
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 12
    Par défaut
    Merci W !
    J'ai donc utilisé un flag pour stopper ma boucle avant de join() mon Thread et ça marche correctement.
    Pour ce qui est de l'architecture de mon code je ne suis pas plus avancé.
    Aurais tu des lectures à me conseiller sur le sujet ?
    Pour ce qui est de "mon idée" d'hériter la classe threading.Thread c'est dans un tuto DVP que j'ai lu ça.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Citation Envoyé par Ahima49 Voir le message
    Pour ce qui est de l'architecture de mon code je ne suis pas plus avancé.
    Aurais tu des lectures à me conseiller sur le sujet ?
    Héritage ou pas est une question de distribution des rôles entre différents objets.
    C'est une question d'OO qui n'est pas spécifique à Python.
    Pour les lectures, il faut aller regarder dans la rubrique ALM.

    Ceci dit, distribuer les rôles entre différents objets est une décision à priori (avant de coder) qui doit répondre à différents besoins/exigences. A partir du moment où vous savez motiver (expliquer pourquoi) vos choix et montrer en quoi ils répondent aux besoins, c'est déjà assez bien.

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

  5. #5
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 12
    Par défaut
    C'est une question d'OO qui n'est pas spécifique à Python.
    Bien sur, c'était une question parallèle car j'avais bien perçu que ma question lié à l'héritage du Thread relevait plutôt de l'organisation que spécifiquement du Python.
    Je vais aller relire quelques fondamentaux car ce qui me paraissait évident à l'époque ne l'est plus pour l'instant après 5 ans sans developper de logiciels.
    Peut être qu'il faut juste que je me dérouille
    Merci de m'avoir orienté vers votre section ALM c'est exactement ce qu'il me fallait.
    Je passe donc mon sujet à résolu.

    Bonne journée W et un grand merci encore car j'imagine que vous faites ça bénévolement.

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

Discussions similaires

  1. [3.x] API - Architecture et bonne pratiques
    Par julienbohy dans le forum Symfony
    Réponses: 1
    Dernier message: 30/05/2016, 10h35
  2. Bonne pratique Thread.sleep()
    Par 0viking0 dans le forum C#
    Réponses: 4
    Dernier message: 21/11/2012, 15h54
  3. Réponses: 5
    Dernier message: 08/06/2009, 23h21
  4. [log4j][débutant] Bonnes pratiques avec les threads ?
    Par scougirou dans le forum Logging
    Réponses: 1
    Dernier message: 13/07/2007, 16h27
  5. [MySQL] Architecture d'un site multilingue - Bonnes pratiques ?
    Par xtd[web] dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 22/03/2007, 17h13

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