Partage
  • Partager sur Facebook
  • Partager sur Twitter

Subprocess et communication

Sujet résolu
    18 juillet 2023 à 14:01:34

    Bonjour,

    Je travaille sur une interface graphique Flask qui permet de lancer une série de scripts de traitements d'images par lots et de montages de films par lots aussi.

    Je lance ces scripts par des subprocess.run ou subprocess.Popen dans des threads pour ne pas bloquer l'interface.

    Dans ces différents scripts, des informations de l'état d'avancement de ces scripts sont envoyées par des print() (chacun peut durer jusqu'à 3/4 d'heure selon le nombre d'images à traiter).

    Je vois bien ces print() dans le terminal, d'ailleurs en subprocess.run j'arrive à les afficher en temps réel mais pas en subprocess.Popen.

    Par contre ce que je ne sais pas faire, c'est récupérer ces print par le script principal en temps réel pour les afficher dans l'interface. J'arrive uniquement à les afficher une fois que le script est fini.

    Ce script test affiche tous les print() en fin de script :

    class TraitementC1(threading.Thread):
    	def __init__(self):
    		super(TraitementC1, self).__init__()
    	def run(self):
    		subProcess = ""
    		subProcess = ExistFileStatut('statutT1.txt')
    		if subProcess == "Ok":
    			result = subprocess.Popen(["python3", "tests/test01.py"], stdout=subprocess.PIPE, bufsize=1)
    			print (result.stdout.readline()) # read the first line
    			for i in range(10): # repeat several times to show that it works
    			    print (result.stdout.readline()) # read output
    
    			print (result.communicate("n\n")[0])

    Celui-là affiche bien les print() dans le terminal en temps réel :

    class TraitementC210830(threading.Thread):
    	def __init__(self):
    		super(TraitementC210830, self).__init__()
    	def run(self):
    		subProcess = ""
    		subProcess = ExistFileStatut('statutT2.txt')
    		if subProcess == "Ok":
    			result = subprocess.run(["python3", "tests/test02.py"])

    Auriez-vous une piste de travail, des tutos permettant de traiter ce que je veux faire ?

    Merci d'avance


    -
    Edité par mao-40 18 juillet 2023 à 14:03:45

    • Partager sur Facebook
    • Partager sur Twitter
      18 juillet 2023 à 14:33:56

      mao-40 a écrit:

      ce que je ne sais pas faire, c'est récupérer ces print par le script principal en temps réel pour les afficher dans l'interface. J'arrive uniquement à les afficher une fois que le script est fini.


      Lorsqu'on print sur un terminal, les caractères sont effectivement affichés lorsque le pilote voit la fin de ligne. Avec un pipe, ça attend un certain nombre de caractères (ou la fermeture du pipe). Pour éviter ça il faut travailler en mode unbuffered ou forcer les flush.

      Travailler en unbuffered se fait par exemple via: subprocess.run(["python3", "-u", "tests/test02.py" ])

      -
      Edité par mps 18 juillet 2023 à 14:35:52

      • Partager sur Facebook
      • Partager sur Twitter
        18 juillet 2023 à 15:42:08

        Salut,

        Voici comment j'utilise subprocess pour récupérer les sorties en temps réel.

        import subprocess
        
        process = subprocess.Popen(["ls"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, encoding="utf-8")
        
        while True:
            realTimeOutput = process.stdout.readline()
            if realTimeOutput:
                print(realTimeOutput)  
            else:
                break


        Edit : Après si je comprends bien, quand tu fais ton traitement par lots, ton programme ne fait que ça, donc par spécialement besoin d'un Thread, il suffit de rediriger la sortie vers ton interface et de la rafraichir dans la boucle while.

        -
        Edité par Garkam 18 juillet 2023 à 16:05:08

        • Partager sur Facebook
        • Partager sur Twitter
          18 juillet 2023 à 17:03:51

          Garkam a écrit:

          Voici comment j'utilise subprocess pour récupérer les sorties en temps réel.

          Remplacez le programme ls par un script Python qui fait:
          import time 
          
          print('debut') 
          time.sleep(60) 
          print('fin')
          Normalement, "debut" devrait s'afficher en même temps que "fin" au bout de 60 secondes. "en temps réel", ce serait voir s'afficher "debut" puis 60s. plus tard voir s'afficher "fin".
          • Partager sur Facebook
          • Partager sur Twitter
            18 juillet 2023 à 17:30:14

            mps a écrit:

            Garkam a écrit:

            Voici comment j'utilise subprocess pour récupérer les sorties en temps réel.

            Remplacez le programme ls par un script Python qui fait:

            import time 
            
            print('debut') 
            time.sleep(60) 
            print('fin')

            Normalement, "debut" devrait s'afficher en même temps que "fin" au bout de 60 secondes. "en temps réel", ce serait voir s'afficher "debut" puis 60s. plus tard voir s'afficher "fin".


            Alors oui mais avec une instruction bloquante comme time.sleep.

            J'ai remplacé ton script nommé time_60 par :

            print('debut')
            for i in range(1, 61):
                print(i)
            print('fin')

            Avec tkinter : 

            import subprocess
            from tkinter import *
            from tkinter import scrolledtext
            
            
            def insert():
                process = subprocess.Popen(["python3 time_60.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, encoding="utf-8")
            
                while True:
                    realTimeOutput = process.stdout.readline()
                    if realTimeOutput:
                        st.insert(INSERT, realTimeOutput)
                        st.see("end")
                        st.update()
                    else:
                        break
                    
            window = Tk()
            
            window.geometry('500x400')
            st = scrolledtext.ScrolledText(window, width=50,  height=10)
            st.pack(fill=BOTH, side=LEFT, expand=True)
            but = Button(window, text="Insert", command=insert)
            but.pack()
            
            window.mainloop()




            -
            Edité par Garkam 18 juillet 2023 à 17:31:52

            • Partager sur Facebook
            • Partager sur Twitter
              18 juillet 2023 à 18:01:06

              Garkam a écrit:

              Alors oui mais avec une instruction bloquante comme time.sleep.

              Si on ne mets pas un certain temps entre le debut et la fin, difficile de montrer qu'on récupère toutes les lignes d'un coup ou au fur et à mesure. Du coup, il n'y a pas de problème....

              S'il n'y a pas de problème, pourquoi le PO poserait sa question et pourquoi proposer une solution identique?

              • Partager sur Facebook
              • Partager sur Twitter
                18 juillet 2023 à 18:13:06

                Là, c'est de la mauvaise foi. :p

                Dans mon exemple, on voit très bien que les lignes sont récupérées une à une.

                Et je n'utilise pas subprocess.run, ni de thread.

                -
                Edité par Garkam 18 juillet 2023 à 18:13:36

                • Partager sur Facebook
                • Partager sur Twitter
                  18 juillet 2023 à 18:33:45

                  Garkam a écrit:

                  Là, c'est de la mauvaise foi. :p

                  Dans mon exemple, on voit très bien que les lignes sont récupérées une à une.

                  Tout à fait... mais est-ce qu'elles sont reçues l'une après l'autre ou toutes à la fois? Ce n'est pas en les lisant une après l'autre qu'on va le savoir: votre code démontre rien (de ce côté).

                  Sans le time.sleep, on ne reproduit pas le problème initial (ça peut durer 3/4 d'heures et ça récupère les états d'avancement à la fin alors que ça fonctionne bien sur un terminal). Et sans avoir compris le problème initial, comment proposer une solution?

                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 juillet 2023 à 18:41:15

                    mps a écrit:

                    Garkam a écrit:

                    Là, c'est de la mauvaise foi. :p

                    Dans mon exemple, on voit très bien que les lignes sont récupérées une à une.

                    Tout à fait... mais est-ce qu'elles sont reçues l'une après l'autre ou toutes à la fois? Ce n'est pas en les lisant une après l'autre qu'on va le savoir: votre code démontre rien (de ce côté).

                    Sans le time.sleep, on ne reproduit pas le problème initial (ça peut durer 3/4 d'heures et ça récupère les états d'avancement à la fin alors que ça fonctionne bien sur un terminal). Et sans avoir compris le problème initial, comment proposer une solution?

                    Ok, mais le time.sleep ne démontre rien non plus, il bloque également le print supérieur car l'interface n'a même pas le temps de se rafraichir.

                    D'accord avec toi pour attendre une réponse du PO, mais si je m'avance c'est que j'ai déjà eu ce type de soucis ;)

                    • Partager sur Facebook
                    • Partager sur Twitter
                      18 juillet 2023 à 19:35:43

                      Garkam a écrit:

                      Ok, mais le time.sleep ne démontre rien non plus, il bloque également le print supérieur car l'interface n'a même pas le temps de se rafraichir.

                      On peut comparer ce qu'il se passe avec le script (avec time.sleep) lancé depuis un terminal et via subprocess et constater la différence entre tout s'affiche à la fin ou au fur et à mesure...

                      Ce qui est le problème décrit par le PO.

                      On peut aussi lancer le subprocess avec l'option -u pour constater que ça s'affiche alors au fur et à mesure.

                      On peut aussi lire la documentation pour comprendre le pourquoi de la chose.

                      Garkam a écrit:

                      mais si je m'avance c'est que j'ai déjà eu ce type de soucis

                      Vu votre réponse, il faudrait peut être retravailler le sujet..

                      .

                      -
                      Edité par mps 18 juillet 2023 à 19:36:03

                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 juillet 2023 à 19:45:59

                        No comment...

                        mps a écrit:

                        Garkam a écrit:

                        Ok, mais le time.sleep ne démontre rien non plus, il bloque également le print supérieur car l'interface n'a même pas le temps de se rafraichir.

                        On peut comparer ce qu'il se passe avec le script (avec time.sleep) lancé depuis un terminal et via subprocess et constater la différence entre tout s'affiche à la fin ou au fur et à mesure...

                        Ce qui est le problème décrit par le PO.

                        On peut aussi lancer le subprocess avec l'option -u pour constater que ça s'affiche alors au fur et à mesure.

                        On peut aussi lire la documentation pour comprendre le pourquoi de la chose.

                        Garkam a écrit:

                        mais si je m'avance c'est que j'ai déjà eu ce type de soucis

                        Vu votre réponse, il faudrait peut être retravailler le sujet..

                        No comment... Mais fais quelque chose (trouve toi une fiancée...)




                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 juillet 2023 à 22:03:41

                          mps a écrit:

                          Travailler en unbuffered se fait par exemple via: subprocess.run(["python3", "-u", "tests/test02.py" ])


                          Super, merci !! ça a l'air de fonctionner dans le terminal, maintenant il faut que j'arrive à l'envoyer dans les spans dédiés de l'interface en temps réel.

                          Garkam a écrit:

                          Edit : Après si je comprends bien, quand tu fais ton traitement par lots, ton programme ne fait que ça, donc par spécialement besoin d'un Thread, il suffit de rediriger la sortie vers ton interface et de la rafraichir dans la boucle while.

                          J'ai simplifié ma question pour le besoin, mais l'interface permet aussi de visualiser/trier par séries de planches les images générées (env 400/jour), effectuer des montages vidéos (timelapses) des images en fonction des types d'images, envoyer des statistiques par mail, et envoyer les images et films traités sur des serveurs distants. Ces opérations peuvent être effectuées en simultanée pour certaines et donc ne pas figer l'interface. Tout en ayant des retours d'avancements des différents scripts lancés pour chaque opération.

                          Je ne sais pas faire sans thread, mais je suis preneur d'idées et conseils

                          -
                          Edité par mao-40 18 juillet 2023 à 22:11:45

                          • Partager sur Facebook
                          • Partager sur Twitter
                            18 juillet 2023 à 22:37:45

                            mao-40 a écrit:

                            Je ne sais pas faire sans thread, mais je suis preneur d'idées et conseils

                            Faites avec le python que vous maîtrisez. Il sera toujours perfectible plus tard si vous en avez le temps.


                            • Partager sur Facebook
                            • Partager sur Twitter
                              19 juillet 2023 à 21:42:23

                              mps a écrit:

                              mao-40 a écrit:

                              Je ne sais pas faire sans thread, mais je suis preneur d'idées et conseils

                              Faites avec le python que vous maîtrisez. Il sera toujours perfectible plus tard si vous en avez le temps.


                              Merci, tout fonctionne comme ça.
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Subprocess et communication

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown