【问题标题】:The effect of time delay on the execution of PyQt5 QThreadPool()时间延迟对PyQt5 QThreadPool()执行的影响
【发布时间】:2020-05-08 09:39:08
【问题描述】:

这里是场景,我使用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],依此类推。 (我已经包含了 sleep 只是为了清楚地阅读输出)。但问题是,当我执行这个程序时,它会在第一次运行时给出以下输出。

[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_())

最后我必须说,我使用了来自网站 Learpyqt.com 的 QThreadPool 部分代码

编辑 1

当我从QTimer 分离函数wait2 并将其绑定到按钮pushButton_2 时,每次单击该按钮时,它都会给出所需的结果。 但我希望它附加QTimer 以自动更新此功能setdata

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

编辑 2

当我从 setdata 函数中删除睡眠时,它会按我的意愿工作。但是由于这个程序是我的大项目的一部分,而不是 time.sleep() 我有多个读取函数,它们从其他 python 文件中读取数据。这会导致延迟,我根本无法消除。因此,即使我在这种情况下删除 time.sleep(),也不能解决我原来的问题。

编辑 3

我正在读取多个传感器,压力、温度、加速度计、陀螺仪、磁力计。每个传感器的读取时间都不同。我优先考虑陀螺仪、加速度计和磁力计以获得最大采样率。当我一次读取所有传感器时,所有这些中最慢的是温度,因此所有传感器都必须等到读取温度。因此,它降低了其他传感器的采样率。这就是我引入 QThreading 的原因,以便我可以将温度、压力与加速度计、磁力计、陀螺仪分开。现在,假设我每 10 毫秒调用一次函数(保持温度和压力),其顺序是它先读取温度,然后读取压力,然后它应该保持这个顺序。但在我的情况下,它有时会覆盖温度并转向压力,有时会读取温度 10 次,然后读取压力一次。这种不规则的读数是基本问题。

编辑 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 个读数/秒。当我从此块中删除温度和压力时 采样率急剧增加到 100 个样本/秒。所以我使用了以下解决方案(目前失败)。

    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)

这使得陀螺仪、加速度计和磁力计的读数独立于温度和压力传感器。所以现在我可以更快地阅读。但是当我尝试绘制温度和压力与时间的关系时。然后它失败了,因为正如我之前所说,温度和压力以不规则的方式读取,这使得各个列表的长度不相等,因此无法绘制

【问题讨论】:

    标签: python pyqt5


    【解决方案1】:

    如果我从字面上理解您的要求,我认为没有“解决方案”,但也许通过我对问题的解释,您会更详细地解释您想要什么,从而为您提供解决方法。子>

    以前的知识:

      1234563启动 QRunnable 并且已经有 4 个活动,那么它不会启动。
    • 我们的眼睛(大脑)速度非常慢,所以不到 30 毫秒的“打印”将被打印为一个块,如果有很多块会发生什么大块?因为我们的大脑会将这些小块连接起来,形成看似连续的东西。结论:我们的眼睛不是进行测量的可靠工具。

    考虑到上述情况,您尝试每 10 毫秒启动一个可运行对象,并且每个可运行对象在“睡眠”时间内实际上保持活动状态,因为打印消耗的时间可以忽略不计,因此活动时间为 5 秒,因此在 40 毫秒后程序启动后,将不会启动任何可运行对象,在这 40 毫秒内,我们的大脑会将 4 个印象视为一个块,而另一个可运行对象只会在 5 秒后启动,因此它会观察到相同的效果。

    没有“睡眠”,与打印时间相比,10 毫秒是很长的时间,所以当你想启动一个新的可运行 I 时,线程数将为 0,因此新线程将启动,因此可以看到连续打印(我们的大脑在欺骗我们)

    【讨论】:

    • 这个线程似乎在做的是,当它看到 time.sleep() (在实际程序中将是一个任务)时,它会跳过它,并立即执行下一个命令,这应该发生在 time.sleep() 之后。
    • 这个跳越 time.sleep() 到下一个命令造成了问题。
    • @Juno 让我解释一下:假设你是 4 个工人的老板,每天都有新的任务来找你,但是每个工人需要 10 天的时间来完成一项任务。如果工人仍然忙于上一个任务,那么第五个任务应该怎么办?
    • @Juno 另一方面,您的解释令人困惑,所以我请您回答我所有的问题:1)如果传感器“A”读取温度和压力,那么传感器“B”读取什么? 2) 每个传感器应该多久读取一次? 3) 读取每个传感器需要多少时间?我问了我之前的问题,因为我使用过温度传感器,读取时间很短,但有时无法读取,在我的情况下,读取需要几毫秒,但必须每 2 秒读取一次。
    • @Juno(例如,如果在 t = 1 x1 已经读取并且 t = 10 X2 被读取,则在 t = 1 和 t = 10 之间,传感器 X1 不应该做任何事情),并且当处理完成,开始读取(如果T3
    猜你喜欢
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多