Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. International
  3. Spanish
  4. ¿Como evitar loops infinitos en GUIs?
Qt 6.11 is out! See what's new in the release blog

¿Como evitar loops infinitos en GUIs?

Scheduled Pinned Locked Moved Unsolved Spanish
7 Posts 4 Posters 2.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Carlos DiazC Offline
    Carlos DiazC Offline
    Carlos Diaz
    wrote on last edited by
    #1

    Que tal,

    Estoy utilizando PySide2 para un proyecto donde recibo datos por comunicación serial desde un microcontrolador.

    Hasta el momento he utilizado este pseudo-código para recibir datos:

    abrir_comunicacion_serial()
    while comunicacion_serial:
        datos = recibir_datos()
    
        si datos == 'end':
            break
        sleep(1)
    
    cerramos_comunicacion_serial()
    procesamos_datos()
    

    El loop while se ejecuta mientras tenga comunicación serial, recibo los datos y evalúo si los datos que recibí son igual a un marcador ('end'), de ser asi salgo del while y continuo con el procesamiento de los datos.

    Funciona, sin embargo la GUI no responde mientras se ejecuta el while infinito, he intentado mandar la recepción de datos a un thread corriendo como daemon (tengo entendido que se ejecuta en el background) pero no he tenido éxito ya que no tengo decidido si los datos los debo procesar en el mismo thread o usar un flag y procesarlos en el thread principal.

    ¿Algún consejo para evitar utilizar loops infinitos que causen que la GUI se torne torpe/no responsiva?

    Saludos!

    Pablo J. RoginaP 1 Reply Last reply
    0
    • juankiJ Offline
      juankiJ Offline
      juanki
      Moderators
      wrote on last edited by
      #2

      Hola

      Yo diría que tienes que procesar los datos en el hilo secundario, si lo haces en el principal tendrás el mismo atasco en la GUI.

      Un saludo

      Intenta explicar el problema lo más claro y detallado posible. Adjunta los errores y el código que creas da el error.
      Procura escribir correctamente y sin faltas de ortografía.

      Si la duda se solucionó, por favor, marca el tema como 'solucionado'.

      1 Reply Last reply
      2
      • O Offline
        O Offline
        ollarch
        wrote on last edited by
        #3

        Mejor utiliza los SIGNALS y SLOTS.

        1 Reply Last reply
        2
        • Carlos DiazC Carlos Diaz

          Que tal,

          Estoy utilizando PySide2 para un proyecto donde recibo datos por comunicación serial desde un microcontrolador.

          Hasta el momento he utilizado este pseudo-código para recibir datos:

          abrir_comunicacion_serial()
          while comunicacion_serial:
              datos = recibir_datos()
          
              si datos == 'end':
                  break
              sleep(1)
          
          cerramos_comunicacion_serial()
          procesamos_datos()
          

          El loop while se ejecuta mientras tenga comunicación serial, recibo los datos y evalúo si los datos que recibí son igual a un marcador ('end'), de ser asi salgo del while y continuo con el procesamiento de los datos.

          Funciona, sin embargo la GUI no responde mientras se ejecuta el while infinito, he intentado mandar la recepción de datos a un thread corriendo como daemon (tengo entendido que se ejecuta en el background) pero no he tenido éxito ya que no tengo decidido si los datos los debo procesar en el mismo thread o usar un flag y procesarlos en el thread principal.

          ¿Algún consejo para evitar utilizar loops infinitos que causen que la GUI se torne torpe/no responsiva?

          Saludos!

          Pablo J. RoginaP Offline
          Pablo J. RoginaP Offline
          Pablo J. Rogina
          wrote on last edited by
          #4

          @Carlos-Diaz said in ¿Como evitar loops infinitos en GUIs?:

          ¿Algún consejo para evitar utilizar loops infinitos que causen que la GUI se torne torpe/no responsiva?

          Nunca usar loops infinitos en Qt/PyQt. Como sugirieron antes, para eso están Signals & Slots

          Upvote the answer(s) that helped you solve the issue
          Use "Topic Tools" button to mark your post as Solved
          Add screenshots via postimage.org
          Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          2
          • Carlos DiazC Offline
            Carlos DiazC Offline
            Carlos Diaz
            wrote on last edited by
            #5

            Gracias a todos por su respuesta, pude hacer una pequeña prueba de concepto donde utilizo threads, signals y slots, la documentación de Qt es muy clara al respecto (Signals and Slots).

            Este es el código que tengo, no estoy muy familiarizado con Python, debe de haber formas más optimas de realizarlo.

            from PySide2.QtCore import *
            from PySide2.QtWidgets import *
            
            import serial
            import serial.tools.list_ports;
            
            from threading import Thread
            
            import sys
            import time
            
            class serialComm(QObject):
                opened = Signal()
                closed = Signal()
                data_received = Signal(str)
            
                def open(self):
                    # Obtiene la lista de puertos seriales de la PC
                    available_ports = serial.tools.list_ports.comports()
            
                    if available_ports:
                        for port in available_ports:
                            if 'COM14' in port.device:
                                self.serial_port = serial.Serial(port.device, 115200)
                                if self.serial_port.is_open:
                                    self.opened.emit()
                                else:
                                    print('Falla al establecer comunicación con el microcontrolador')
            
                    serialReaderThread = Thread(target = self.read, daemon = True)
                    serialReaderThread.start()
                    
                def close(self):
                    if self.serial_port.is_open:
                        self.serial_port.close()
                        if self.serial_port.is_open == False:
                            self.closed.emit()
            
                def write(self, data):
                    self.serial_port.write(data.encode())
            
                def read(self):
                    while True:
                        while self.serial_port.is_open:
                            data = self.serial_port.readline()
                            print(data)
                            self.data_received.emit(data.decode())
            
                            if 'end' in data.decode():
                                break
            
                            time.sleep(.5)
            
                        break
            
                    print('All serial data received')
            
            @Slot()
            def print_hello():
                print('Puerto serial abierto')
            
            @Slot()
            def print_goodbye():
                print('Puerto serial cerrado')
            
            app = QApplication([])
            text_area = QTextEdit()
            
            @Slot(str)
            def display_data(msg):
                text_area.append(msg)
            
            if __name__ == "__main__":
            
                my_serial = serialComm()
                my_serial.opened.connect(print_hello)
                my_serial.closed.connect(print_goodbye)
                my_serial.data_received.connect(display_data)
            
                my_serial.open()
            
                # GUI
                layout = QVBoxLayout()
                layout.addWidget(text_area)
                
                window = QWidget()
                window.setLayout(layout)
                window.show()
            
                sys.exit(app.exec_())
            

            Y una captura del script corriendo:
            alt text

            ¿Se podría 'mejorar' el código?

            Saludos

            1 Reply Last reply
            0
            • O Offline
              O Offline
              ollarch
              wrote on last edited by ollarch
              #6

              Hola, no soy programador de Python, soy de C++.
              Como te dije antes, utiliza los SIGNALS y SLOTS. Estas utilizando un Thread con un sleep de 5ms y esto consume mucha CPU. Conecta el SIGNAL "readyRead" del puerto serie "my_serial" y en el SLOT procesa lo que tengas que hacer. Si los datos que recibes tienen que ser procesados y el proceso es muy complejo luego si que deberías pensar en utilizar Threads pero si no lo es te aconsejo que dejes el procesado de datos en el Main Thread.

              Ejecuta tu programa y mira cuanta CPU está utilizando (si eliminas el sleep lo verás mejor). Es un simple programa que lee del puerto serie y seguro que la CPU está alta(dependerá del numero de CPUs que tengas. Si por ejemplo tienes 4 CPUs verás que tu programa casi llega al 25% de CPU que es el uso de todo un núcleo). Te recomiendo evitar siempre que puedas los sleeps dentro de un thread.

              1 Reply Last reply
              1
              • Carlos DiazC Offline
                Carlos DiazC Offline
                Carlos Diaz
                wrote on last edited by
                #7

                Hola,

                Miré con el administrador de tareas la CPU que consume el script al ejecutarse y consume ~2.5%, aunque no estoy seguro de que esta sea la forma más segura de consultar esos datos. Igual revisaré el consumo en la PC donde se va a ejecutar el script, es más vieja entonces debería de consumir más recursos.

                @ollarch said in ¿Como evitar loops infinitos en GUIs?:

                Hola, no soy programador de Python, soy de C++.
                Como te dije antes, utiliza los SIGNALS y SLOTS. Estas utilizando un Thread con un sleep de 5ms y esto consume mucha CPU. Conecta el SIGNAL "readyRead" del puerto serie "my_serial" y en el SLOT procesa lo que tengas que hacer. Si los datos que recibes tienen que ser procesados y el proceso es muy complejo luego si que deberías pensar en utilizar Threads pero si no lo es te aconsejo que dejes el procesado de datos en el Main Thread.

                El "problema" es que el binding de QSerialPort no esta disponible en PySide2 y estoy utilizando el módulo pyserial, igual creé tres señales, opened, closed y data_received con la que comunico mi clase serialComm con la aplicación, voy a investigar si hay forma de que pyserial me diga cuando hay datos disponibles y asi evitar tener el while True.

                Saludos

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved