【发布时间】:2020-03-01 03:15:21
【问题描述】:
我正在使用 pyqtgraph 绘制从传感器接收到的大量数据。
为此,我创建了一个线程来获取数据并放入队列中。为了绘制数据,如果队列不为空,我会使用计时器定期检查。 问题是计时器(QTimer)的准确性似乎非常糟糕。我的意思是当测量线程中的负载较低(睡眠 1000/100 毫秒)时,精度很好,但是当负载增加(睡眠 10 毫秒)时,我用于绘制数据的更新函数不会被回调期间。
这是一个示例代码:
import sys
import time
from queue import Queue
from random import random
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtWidgets
data_queue = Queue()
class WorkerThread(QtCore.QThread):
def __init__(self, parent):
super(WorkerThread, self).__init__(parent=parent)
def run(self):
t_init = time.time()
while True:
# Generating random data
values = [(time.time()-t_init, random()) for _ in range(200)]
data_queue.put(values)
print("adding data")
self.msleep(10)
class GraphPlot(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(GraphPlot, self).__init__(parent)
self.mainbox = QtWidgets.QWidget()
self.setCentralWidget(self.mainbox)
self.mainbox.setLayout(QtWidgets.QVBoxLayout())
self.canvas = pg.GraphicsLayoutWidget()
self.mainbox.layout().addWidget(self.canvas)
self.analogPlot = self.canvas.addPlot(title='Real-time data')
self.drawplot = self.analogPlot.plot(pen='r')
numPoints = 20000
self.t = np.zeros(numPoints, dtype=int)
self.x = np.zeros(numPoints, dtype=int)
self.worker = WorkerThread(self)
self.worker.start()
self.timer = pg.QtCore.QTimer()
self.timer.setTimerType(QtCore.Qt.PreciseTimer)
self.timer.timeout.connect(self._update)
self.timer.start(1)
def _update(self):
print('start:', time.time())
size = data_queue.qsize()
if size > 0:
for _ in range(size):
values = data_queue.get()
for v in values:
self.t = np.append(self.t[1:], v[0])
self.x = np.append(self.x[1:], v[1])
self.drawplot.setData(self.t, self.x)
print('end:', time.time())
app = QtWidgets.QApplication(sys.argv)
plot = GraphPlot()
plot.show()
sys.exit(app.exec_())
输出的摘录:
start: 1572893919.9067862
adding data
end: 1572893919.9217482 <--
adding data
start: 1572893919.9586473 <-- there should be 1ms of difference with last 'end'
actually, there is around 37ms
无论测量线程上的负载如何,我都希望计时器与同一周期同步。我尝试降低前一个线程的优先级,但并没有解决问题。
【问题讨论】:
-
您想要更低的延迟?操作系统可以实现的延迟有一个限制,发生了很多事情,如果您正在运行线程并且存在上下文切换、页面错误等,那么 1ms 非常低,您很可能会遇到一些抖动在这种情况下,或者永远不会得到 1 毫秒的延迟,
-
好吧 QTimer 是一个异步函数——对我来说这意味着独立的进程,因为它似乎不受 Python 线程 GIL 的影响——而且它是事件驱动的,因此它的调用被放置在事件处理程序队列然后在事件处理程序到达它时进行处理,这可能会受到许多事情的影响——始终如一地获得 1ms 延迟的唯一方法是在事件处理程序之外执行——这意味着你以某种方式将它放在线性代码中。我知道的细节不多,但是有无数种方法可以做到这一点,没有一种是明显错误的,只是由于不同的原因而不同