Влияние временной задержки на выполнение PyQt5 QThreadPool () - PullRequest
0 голосов
/ 08 мая 2020

Вот сценарий, я использую QThreadPool для параллельного выполнения различных функций. У меня есть список с именем self.firstRun = [] и функция, в которой этот список используется следующим образом.

def setdata(self):
  self.firstRun.append(1)
  print(self.firstRun)
  time.sleep(5)

эта функция вызывается другой функцией с именем wait2, которая

def wait2(self):
   worker = Worker(self.setdata)
   self.threadpool.start(worker)

как можно видеть, функция wait2 вызывает класс Worker и отправляет функцию setdata этому классу для потоковой передачи. Когда я выполняю эту программу, я ожидаю, что функция setdata выдаст мне [1] в качестве вывода при первом запуске и [1,1] во втором и так далее. (Я включил режим сна только для четкого чтения вывода). Но проблема в том, что когда я запускаю эту программу, она при первом запуске дает следующее.

[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]

Я хочу, чтобы программа сначала выдавала [1], а затем при дальнейшем выполнении она должна выдавать мне список с одним приращением. Вот полный код

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import*
from PyQt5.QtWidgets import*
from PyQt5.QtCore import*
from pyqtgraph import PlotWidget
import time
import numpy as np

class Worker(QRunnable):
    def __init__(self, fn, *args, **kwargs):
        super(Worker, self).__init__()
        self.fn = fn
        self.args = args
        self.kwargs = kwargs

    @pyqtSlot()
    def run(self):
        result = self.fn(*self.args,**self.kwargs)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1000, 800)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.widget = PlotWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(19, 19, 300, 300))
        self.widget.setObjectName("widget")
        self.widget_2 = PlotWidget(self.centralwidget)
        self.widget_2.setGeometry(QtCore.QRect(350, 20, 300, 300))
        self.widget_2.setObjectName("widget_2")
        self.widget_3 = PlotWidget(self.centralwidget)
        self.widget_3.setGeometry(QtCore.QRect(680, 20, 300, 300))
        self.widget_3.setObjectName("widget_3")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(40, 420, 141, 41))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(210, 420, 141, 41))
        self.pushButton_2.setObjectName("pushButton_2")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(50, 490, 311, 31))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(40, 540, 61, 21))
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(170, 540, 61, 21))
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(300, 540, 61, 21))
        self.label_4.setAlignment(QtCore.Qt.AlignCenter)
        self.label_4.setObjectName("label_4")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.firstRun = []
        self.x = []
        self.y = []
        self.data_line1 = self.widget.plot(self.x,self.y)

        self.timer = QtCore.QTimer()
        self.timer.setInterval(10)
        self.timer.timeout.connect(self.wait2)
        self.timer.start()


        self.threadpool = QThreadPool()  

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Start"))
        self.pushButton_2.setText(_translate("MainWindow", "Stop"))
        self.label.setText(_translate("MainWindow", "Text"))
        self.label_2.setText(_translate("MainWindow", "TextLabel"))
        self.label_3.setText(_translate("MainWindow", "TextLabel"))
        self.label_4.setText(_translate("MainWindow", "TextLabel"))

    def wait2(self):
        worker = Worker(self.setdata)
        self.threadpool.start(worker)

    def setdata(self):
        self.firstRun.append(1)
        print(self.firstRun)
        time.sleep(5)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

В последнем я должен сказать, что я использовал часть кода QThreadPool с веб-сайта Learpyqt.com

Edit 1

Когда я отсоединяю функцию wait2 от QTimer и привязываю ее к кнопке pushButton_2, то каждый раз, когда я нажимаю кнопку, это дает желаемый результат. Но я хочу, чтобы он был прикреплен к QTimer, чтобы эта функция setdata обновлялась автоматически.

self.pushButton_2.clicked.connect(self.wait2)

Edit 2

Когда я удаляю сон из setdata функция тогда работает как я хочу. Но поскольку эта программа является частью моего большого проекта, в котором вместо time.sleep () у меня есть несколько функций чтения, которые считывают данные из других python файлов. Это вызывает задержку, которую я просто не могу устранить. Таким образом, даже если я удалю time.sleep () в этом случае, это не решит мою исходную проблему.

Edit 3

Я читаю несколько датчиков, давление , Температура, акселерометр, гироскоп, магнитометр. Время считывания разное для каждого из этих датчиков. Я отдаю предпочтение гироскопу, акселерометру и магнитометру, чтобы получить максимальную частоту дискретизации. Когда я считываю данные со всех датчиков одновременно, самым медленным из них является температура, поэтому все датчики должны ждать, пока не будет считана температура. Таким образом, это снижает частоту дискретизации других датчиков. Вот почему я ввел QThreading, чтобы я мог отделить температуру, давление от акселерометра, магнитометра и гироскопа. Теперь предположим, что я вызываю функцию (которая удерживает температуру и давление) каждые 10 мс в таком порядке, что сначала она считывает температуру, а затем давление, а затем должна поддерживать этот порядок. Но в моем случае он иногда переопределяет температуру и переходит к давлению, а иногда считывает температуру 10 раз, а затем 1 раз давление. Это нерегулярное чтение является основной проблемой c.

Редактировать 4

Это то, что я делал ранее

self.timer_1 = QtCore.QTimer()
self.timer_1.setInterval(1)
self.timer_1.timeout.connect(self.getValues)
self.timer_1.start()

self.timer_2 = QtCore.QTimer()
self.timer_2.setInterval(10)
self.timer_2.timeout.connect(self.UpdatePlot_1)
self.timer_2.start()

self.timer_3 = QtCore.QTimer()
self.timer_3.setInterval(10)
self.timer_3.timeout.connect(self.UpdatePlot_2)
self.timer_3.start()

def UpdatePlot_1(self):
    if self.Lstartbutton:
        self.plot_1.setData(self.t,self.temperature)
        self.plot_2.setData(self.t,self.pressure)

def UpdatePlot_2(self):
    if self.Lstartbutton:
        self.plot_3.setData(self.t,self.roll)
        self.plot_4.setData(self.t,self.rollDrift)
        self.plot_5.setData(self.t,self.rollAccel)


def getValues(self):
     if len(self.firstRun) <= 50:      
          self.firstRun.append(1)
          self.t         = np.arange(1,len(self.firstRun)+1)
          gyro2.updateGyroValues()
          gyro2.updateHeadings()
          xi,yi,xii,yii,zii,s1,s2    = gyro2.printHeadings()
          xiii,yiii,ziii = compass.axes()
          temperature    = sensor.read_temperature()
          pressure       = sensor.read_pressure()
          self.temperature.append(temperature)
          self.pressure.append(pressure)
          self.roll.append(xii)
          self.rollDrift.append(s1)
          self.pitch.append(yii)
          self.pitchDrift.append(s2)
          self.rollAccel.append(xi)
          self.pitchAccel.append(yi)

     else:
         self.t = list(self.t)
         self.firstRun1.append(1)
         self.t = self.t[1:]
         self.t.append(self.t[-1]+1)
         gyro2.updateGyroValues()
         gyro2.updateHeadings()
         xi,yi,xii,yii,zii,s1,s2 = gyro2.printHeadings()
         xiii,yiii,ziii = compass.axes()
         temperature = sensor.read_temperature()
         pressure    = sensor.read_pressure()
         self.temperature = self.temperature[1:]
         self.pressure    = self.pressure[1:]
         self.pressure.append(pressure)
         self.temperature.append(temperature)
         self.roll = self.roll[1:]
         self.pitch = self.pitch[1:]
         self.rollDrift = self.rollDrift[1:]
         self.pitchDrift = self.pitchDrift[1:]
         self.rollAccel = self.rollAccel[1:]
         self.pitchAccel = self.pitchAccel[1:]
         self.roll.append(xii)
         self.rollDrift.append(s1)
         self.pitch.append(yii)
         self.pitchDrift.append(s2)
         self.rollAccel.append(xi)
         self.pitchAccel.append(yi)

Этот подход гласит все датчики работают одинаково. Частота дискретизации в этом случае составляет 9 показаний / сек c. Когда я удаляю из этого блока температуру и давление, частота дискретизации резко увеличивается до 100 выборок в секунду c. Поэтому я использовал следующее решение (пока не удалось).

    self.timer_2 = QtCore.QTimer()
    self.timer_2.setInterval(1)
    self.timer_2.timeout.connect(self.thread_2)
    self.timer_2.start()

def getValues2(self):
    temperature    = sensor.read_temperature()
    pressure       = sensor.read_pressure()
    self.temperature.append(temperature)
    self.pressure.append(pressure)

def thread_2(self):
    worker = Worker(self.getValues2)
    self.threadpool.start(worker)

Это сделало показания гироскопа, акселерометра и магнитометра независимыми от датчика температуры и давления. Так что теперь я могу читать намного быстрее. Но когда я пытаюсь построить график зависимости температуры и давления от времени. Затем он терпит неудачу, потому что, как я сказал ранее, температура и давление считываются нерегулярно, что делает длину соответствующих списков неравной, поэтому не может быть нанесен на график

1 Ответ

1 голос
/ 08 мая 2020

Я не думаю, что есть «решение», если я воспринимаю ваши требования буквально, но, возможно, с моим объяснением проблемы вы объясните более подробно, что вы хотите, и, таким образом, предложите вам обходной путь.

Предыдущие знания:

  • A QThreadPool может использовать максимальное количество потоков, которое может быть известно через maxThreadCount свойство, которое в моем случае равно 4, и я полагаю, что оно есть и у вас, поэтому, если вы попытаетесь запустить QRunnable и уже есть 4 активных объекта, тогда нет start.

  • Наши глаза (мозг) работают очень медленно, поэтому «отпечатки», которые занимают менее 30 мс, будут распечатаны как блок, и что произойдет, если блоков будет много, так это большой? потому что наш мозг объединяет эти маленькие блоки для того, что кажется непрерывным. Вывод: наши глаза не являются надежным инструментом для проведения измерений.

Учитывая вышесказанное, вы пытаетесь запускать исполняемый объект каждые 10 мс, и каждый исполняемый объект остается практически активным во время «сна» время, так как время, затрачиваемое на печать, незначительно, поэтому активное время составляет 5 секунд, поэтому через 40 мсек. После запуска программы ни один запускаемый файл не запускается, и в течение этих 40 мс наш мозг рассматривает 4 отпечатка как блок, а еще один запускаемый начнется только через 5 секунд, поэтому будет наблюдаться тот же эффект.

Без «сна» 10 мс - это долгое время по сравнению со временем печати, поэтому, когда вы хотите запустить новый запускаемый I, количество потоки будут равны 0, поэтому новый поток запустится, и, следовательно, будет видна непрерывная печать (наш мозг обманывает нас)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...