Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Pyqt UI non responsive on Multithreading with python
Forum Updated to NodeBB v4.3 + New Features

Pyqt UI non responsive on Multithreading with python

Scheduled Pinned Locked Moved Unsolved Qt for Python
15 Posts 3 Posters 3.1k 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.
  • A Albitroz

    I'm new to PyQt and python, i was working with a program which had a simple UI and which collects some data from a hardware

    I have 2 files handling everything and a thread to collect data , but my problem is that, when thread is running, UI becomes un responsive..

    All UI portion is handled by file "Analog_ui.py"
    All data capture portion is handled by file "AI_DAQ.py"

    Code for Analog_ui.py

    
    "___________________________Create GUI____________________________________________"
    from itertools import starmap
    import sys
    
    #import QApplications and the required widgets from PyQt.QtWidgets
    from PyQt5 import QtWidgets,QtCore, QtGui
    from PyQt5.QtCore import Qt
    from PyQt5.QtWidgets import QGridLayout, QLineEdit
    from PyQt5.QtWidgets import QVBoxLayout
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWidgets import QLabel, QHBoxLayout, QPushButton
    from PyQt5.QtWidgets import QWidget
    from PyQt5.QtWidgets import QMainWindow
    from PyQt5 import uic
    import AI_DAQ
    
    
    
    #exec(open("Analogdata.py").read()) 
    
    class Configure_MainWindow(object): 
        
        def Ui_Configure(self, MainWindow):
            MainWindow.resize(1100,600)
            self.centralwidget=QtWidgets.QWidget(MainWindow)
            
            #adding start and stop pushbutton
            self.pushButton1=QtWidgets.QPushButton(self.centralwidget)
            self.pushButton1.setGeometry(QtCore.QRect(1000,500,93,28))
            
            
            self.pushButton2=QtWidgets.QPushButton(self.centralwidget)
            self.pushButton2.setGeometry(QtCore.QRect(1000,550,93,28))
            
            self.Physicalchannel=QtWidgets.QLineEdit(self.centralwidget)
            self.Physicalchannel.setGeometry(QtCore.QRect(40,50,140,21))
            self.Physicalchannel.setText("Dev1/ai0")
            #self.Physicalchannel.
       
            
            self.PhysicalchannelLabel=QtWidgets.QLabel(self.centralwidget)
            self.PhysicalchannelLabel.setGeometry(QtCore.QRect(40,25,111,21))
            
            self.MaxVolt=QtWidgets.QSpinBox(self.centralwidget)
            self.MaxVolt.setGeometry(QtCore.QRect(190,120,100,21))
            self.MaxVolt.setRange(0,5)
            self.MaxVolt.setValue(5)
            self.MaxVoltLabel=QtWidgets.QLabel(self.centralwidget)
            self.MaxVoltLabel.setGeometry(QtCore.QRect(190,90,60,28))
            
            self.MinVolt=QtWidgets.QSpinBox(self.centralwidget)
            self.MinVolt.setGeometry(QtCore.QRect(40,120,100,21))
            self.MinVolt.setRange(-5,0)
            self.MinVolt.setValue(-5)
            self.MinVoltLabel=QtWidgets.QLabel(self.centralwidget)
            self.MinVoltLabel.setGeometry(QtCore.QRect(40,90,60,28))
            
            self.SampleRate=QtWidgets.QSpinBox(self.centralwidget)
            self.SampleRate.setGeometry(QtCore.QRect(220,50,70,21))
            self.SampleRate.setRange(0,400)
            self.SampleRate.setValue(200)
            
            self.SampleRateLabel=QtWidgets.QLabel(self.centralwidget)
            self.SampleRateLabel.setGeometry(QtCore.QRect(220,25,60,28))
            
            """self.graphicsView= QtWidgets.QGraphicsView(self.centralwidget)
            self.graphicsView.setGeometry(QtCore.QRect(265,10,321,281))
            self.graphicsViewLabel=QtWidgets.QLabel(self.centralwidget)
            self.graphicsViewLabel.setGeometry(QtCore.QRect(100,10,60,10))"""
            
            
            MainWindow.setCentralWidget(self.centralwidget)
            
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
            
        def start(self):
            print("start button clicked")
            #a=self.SampleRate.get()
            
            AI_DAQ.cfg_read_task("Dev1/ai0")
             
            
        def stop(self):
            print("Stopping Tread")
            AI_DAQ.stop_task()
            
            
            
            
               
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "Analog Data Acquisition"))
            self.pushButton1.setText(_translate("MainWindow", "Start"))
            self.pushButton2.setText(_translate("MainWindow","Stop"))
            self.PhysicalchannelLabel.setText(_translate("MainWindow","Physical Channel"))
            self.MaxVoltLabel.setText(_translate("MainWindow","Max Voltage"))
            self.MinVoltLabel.setText(_translate("MainWindow", "Min Voltage"))
            self.SampleRateLabel.setText(_translate("MainWindow","Rate"))
            #self.graphicsViewLabel.setText(_translate("MainWindow","AnalogWave form"))
            
            self.pushButton1.clicked.connect(self.start)
            self.pushButton2.clicked.connect(self.stop)
            
                   
        
                    
    """_______________Main function_________________ """  
    
    
    if __name__=='__main__':
        
        #Create an instance of QApplication
        app=QtWidgets.QApplication(sys.argv)
        MainWindow=QtWidgets.QMainWindow()
        # Show GUI
        ui=Configure_MainWindow()
        ui.Ui_Configure(MainWindow) 
        MainWindow.show() #Windows are hidden by default
        #Execute the eventloop
        sys.exit(app.exec_())
        
    
        
    
    

    Code for AI_DAQ.py

    import threading
    from turtle import delay
    from matplotlib.pyplot import get
    import nidaqmx
    from nidaqmx import constants
    import nidaqmx.system
    import time
    
    #variables declaration
    buffer_in_size=100
    buffer_in_size_cfg = round(buffer_in_size * 1)
    task_in=nidaqmx.Task()
    running=True
    
    
            
    def stop_task():
        running=False  
     
           
    def ai_read():
        print("Inside Thread")
        task_in.start()
        while(running):
                data=task_in.read(number_of_samples_per_channel=100)
                #print(data)
                time.sleep(.01)
          
                
        task_in.stop()
        #task_in.close()   
        
    
    def cfg_read_task(chname):
        print(chname)
        running=True
        #configure and setup the AItask
        system=nidaqmx.system.System.local()
        device=system.devices['Dev1']
        phys_chan=device.ai_physical_chans['ai0']
        
        task_in.ai_channels.add_ai_voltage_chan(chname,min_val=-5,max_val=5)
        task_in.timing.cfg_samp_clk_timing (rate=100,sample_mode=constants.AcquisitionType.CONTINUOUS,samps_per_chan=buffer_in_size_cfg)
        print("Task configured")
        #configure thread starting
        thread_ai=threading.Thread(target=ai_read)
        thread_ai.start()
        thread_ai.join()
        
        
    

    here when we start the thread in AI_DAQ.py the whole UI freezes
    How can i resolve the same?

    i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by
    #2

    @Albitroz
    start() calls cfg_read_task(). That calls thread_ai.start() but then immediately thread_ai.join(). Which blocks waiting on the task to complete, and that in turn blocks the UI.

    If you need to use a thread let it run as a thread, not block till it completes.

    i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

    Use Qt signals & slots.

    A 1 Reply Last reply
    1
    • A Offline
      A Offline
      Albitroz
      wrote on last edited by
      #3

      Hi thanks for the solution, it worked.
      Qt signals & slots., i was planing to use queue instead, is that a bad idea?

      A 1 Reply Last reply
      0
      • A Albitroz

        Hi thanks for the solution, it worked.
        Qt signals & slots., i was planing to use queue instead, is that a bad idea?

        A Offline
        A Offline
        Albitroz
        wrote on last edited by
        #4

        @Albitroz said in Pyqt UI non responsive on Multi threading with python:

        Hi thanks for the solution, it worked.
        Qt signals & slots., i was planing to use queue instead, is that a bad idea?

        specifically, to transfer data which is generated by thread

        JonBJ 1 Reply Last reply
        0
        • A Albitroz

          @Albitroz said in Pyqt UI non responsive on Multi threading with python:

          Hi thanks for the solution, it worked.
          Qt signals & slots., i was planing to use queue instead, is that a bad idea?

          specifically, to transfer data which is generated by thread

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #5

          @Albitroz
          You can use a queue, that in itself is fine. You should also be careful to mutex, either code yourself or it must be built into the queue.

          The signal/slot would be needed at least to let the other side know (in your case, the main thread) that new data has been queued. How else would you intend to do that bit?

          A 1 Reply Last reply
          0
          • JonBJ JonB

            @Albitroz
            You can use a queue, that in itself is fine. You should also be careful to mutex, either code yourself or it must be built into the queue.

            The signal/slot would be needed at least to let the other side know (in your case, the main thread) that new data has been queued. How else would you intend to do that bit?

            A Offline
            A Offline
            Albitroz
            wrote on last edited by
            #6

            @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

            JonBJ 1 Reply Last reply
            0
            • JonBJ JonB

              @Albitroz
              start() calls cfg_read_task(). That calls thread_ai.start() but then immediately thread_ai.join(). Which blocks waiting on the task to complete, and that in turn blocks the UI.

              If you need to use a thread let it run as a thread, not block till it completes.

              i would also like to know, how i can pass the data from AI_DAQ.py to Analog_ui.py

              Use Qt signals & slots.

              A Offline
              A Offline
              Albitroz
              wrote on last edited by
              #7

              @JonB in the same code, im facing issues in stopping my thread,
              im calling a function from my main code

              def stop_task():
                  running=False
              

              which will set the running variable to False, and in my thread, im checking for that variable

              def ai_read():
                  print("Inside Thread")
                  task_in.start()
                  while(running):
                          data=task_in.read(number_of_samples_per_channel=100)
                          #print(data)
                          time.sleep(.01)
              

              I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

              JonBJ 1 Reply Last reply
              0
              • A Albitroz

                @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #8

                @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

                It will work, bit it's not as efficient as it could be.

                To do that, your main thread will have to have that interval timer and check each time. Plus often(?) the queue will not be of that size, and it will be a waste of time. Wouldn't you like to know when the thread actually pushes another item to the queue, and only check then/when the count is reached? That is what having the thread send a signal (when it queues), and the main thread have a slot attached to the signal, would achieve.

                The only time where "timed-polling" is (almost) just as good is if you only want the receiver to pull from the queue at those interval points, not as soon as the data arrives. All in all it's hard to see why signalling would not be a preferable solution.

                Sooner or later you will have to use signals & slots in Qt programming, so why not now?

                A 1 Reply Last reply
                0
                • A Albitroz

                  @JonB in the same code, im facing issues in stopping my thread,
                  im calling a function from my main code

                  def stop_task():
                      running=False
                  

                  which will set the running variable to False, and in my thread, im checking for that variable

                  def ai_read():
                      print("Inside Thread")
                      task_in.start()
                      while(running):
                              data=task_in.read(number_of_samples_per_channel=100)
                              #print(data)
                              time.sleep(.01)
                  

                  I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #9

                  @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                  I have verified the value of running with printf inside the thread, its not getting updated, is there any thread safe variable?

                  All your threading stuff is being done with Python threading. So your questions are best asked in a Python forum. I don't know when stop_task() gets called while ai_read() is in a loop.

                  Up to you, but I would use Qt signals & slots for everything like this.

                  1 Reply Last reply
                  0
                  • JonBJ JonB

                    @Albitroz said in Pyqt UI non responsive on Multithreading with python:

                    @JonB i was planing to check the queue size at the other end at a pre defined interval, if queue size is greater than a pre defined size, i just dequeue my queue and get the data. thats my plan is that possible?

                    It will work, bit it's not as efficient as it could be.

                    To do that, your main thread will have to have that interval timer and check each time. Plus often(?) the queue will not be of that size, and it will be a waste of time. Wouldn't you like to know when the thread actually pushes another item to the queue, and only check then/when the count is reached? That is what having the thread send a signal (when it queues), and the main thread have a slot attached to the signal, would achieve.

                    The only time where "timed-polling" is (almost) just as good is if you only want the receiver to pull from the queue at those interval points, not as soon as the data arrives. All in all it's hard to see why signalling would not be a preferable solution.

                    Sooner or later you will have to use signals & slots in Qt programming, so why not now?

                    A Offline
                    A Offline
                    Albitroz
                    wrote on last edited by
                    #10

                    @JonB ok i will use signals and slots as a callback to get the data, but im facing issues stopping the thread

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by SGaist
                      #11

                      Hi,

                      What issues are you having ?

                      Note that depending on what you do in your loop you should put break statement at regular intervals to allow for an easier way out of it.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      A 1 Reply Last reply
                      0
                      • SGaistS SGaist

                        Hi,

                        What issues are you having ?

                        Note that depending on what you do in your loop you should put break statement at regular intervals to allow for an easier way out of it.

                        A Offline
                        A Offline
                        Albitroz
                        wrote on last edited by
                        #12

                        @SGaist HI
                        Currently im facing issues, in transferring data from different threads

                        Im splitting my entire project to different ".py " file for easy debugging, in this case how can i transfer data from one file to other

                        to be pressie,

                        I have my main ".py file which runs the pyqt event loop, i have another file which generates some data through a thread". How can i pass data from this thread to my main python file, can i use signals and slots to transfer data to the main file which holds the UI

                        my main intention is to send data from different threads to the main file which runs QT event and UI so that i can display data from these threads

                        which is better, implementing a queue or signals and slots?

                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #13

                          The files play no role here.

                          If you are using QThread then you can easily use signals and slots to transfert data.

                          Otherwise are you using Python's multithreading or multiprocessing ? If you really want parallel processing with Python, you shall use the later.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          A 1 Reply Last reply
                          0
                          • SGaistS SGaist

                            The files play no role here.

                            If you are using QThread then you can easily use signals and slots to transfert data.

                            Otherwise are you using Python's multithreading or multiprocessing ? If you really want parallel processing with Python, you shall use the later.

                            A Offline
                            A Offline
                            Albitroz
                            wrote on last edited by
                            #14

                            @SGaist
                            I will be handling around 20 threads of different functionalities, and all are time critical activities, so stack overflow suggests using Multiprocessing library which one do you prefer?

                            if i go with multiprocessing library, how can i transfer data between files , my main action is to display these processed data on UI and thats the reason i use PyQt

                            1 Reply Last reply
                            0
                            • SGaistS Offline
                              SGaistS Offline
                              SGaist
                              Lifetime Qt Champion
                              wrote on last edited by
                              #15

                              You can check this article. At the there's a link for a mix between PyQt and multiprocessing.

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              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