时间延迟对 PyQt5 QThreadPool() 执行的影响



这是场景,我正在使用QThreadPool在parrallel中执行不同的功能。我有一个名为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

编辑 1

当我将函数wait2QTimer分离并将其绑定到按钮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)

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

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

以前的知识:

  • QThreadPool可以使用可以通过maxThreadCount属性知道的最大线程数,在我的例子中是 4,我想它也在你的线程中,所以如果你尝试启动一个QRunnable并且已经有 4 个活动,那么不,它会启动。

  • 我们的眼睛(大脑)非常慢,所以不到30毫秒的"打印"将被打印成一个块,如果有很多块会怎样?因为我们的大脑会把这些小块联合起来,看起来是连续的。结论:我们的眼睛不是进行测量的可靠工具。

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

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

最新更新