Документация QTimer частично отвечает на ваш вопрос:
Все типы таймеров могут превысить время ожидания, чем ожидалось, если система занята или не может предоставитьЗапрашиваемая точность. В таком случае превышения тайм-аута, Qt выдаст timeout () только один раз, даже если истекло несколько тайм-аутов, и затем возобновит исходный интервал.
Проблема в том, что после того, как вы вызовете _update
по истечении времени ожидания Qt потребуется некоторое время для обработки того, что происходит после self.drawplot.setData()
, который в основном вычисляет графическую информацию и фактически выводит ее на экран.
Вы не получаете задержку в 1 мс, потому что Qt просто неможет работать так быстро.
Даже если QTimer может работать в другом потоке («асинхронно», но будьте осторожны со значением этого слова), он всегда зависит от того, в каком потоке он создан или находится (QTimer не может быть запущен или остановлен из потока, отличного от его). Итак, поскольку вы создали таймер в потоке окна (основной цикл событий Qt), его точность тайм-аута зависит от способности этого цикла обрабатывать все его событий, а также потому, что многие события связаны между собой. Что касается рисования в графическом интерфейсе (которое кажется быстрым на наш взгляд, но на самом деле медленное , поскольку оно очень требовательно для процессора), вы можете легко понять, почему вы никогда не получите этот интервал в 1 мс. И не забывайте тот факт, что даже если pyqtgraph очень быстрый, мы все еще говорим о Python.
Хотя возможно достижение большей точности для QTimer 1 мс (для него создается отдельный поток), вы быв любом случае от этого не получится никаких преимуществ: даже с очень быстрым компьютером вам необходимо обновить экран на частоте 1000 Гц, в то время как большинство графического оборудования не может работать намного быстрее, чем 100-200 Гц;это означает, что даже если вы владеете высокопроизводительной системой, вы не получите более одного обновления каждые 4 мс.
Если вам нужно обновлять график каждый раз, когда появляются новые данные, вероятно, лучше использоватьсигналы и слоты, что также позволяет избежать ненужной проверки очереди и обеспечивает обновление графика по мере необходимости:
class WorkerThread(QtCore.QThread):
newData = QtCore.pyqtSignal(object)
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)]
print("adding data")
self.newData.emit(values)
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.newData.connect(self.newData)
self.worker.start()
def newData(self, data):
print('start:', time.time())
for v in data:
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())
Вы не получите обновление 1 мс, но в этом не будет необходимоститак или иначе;Кроме того, помните, что печать с такой скоростью всегда будет каким-то образом влиять на производительность.
Наконец, нет никакого преимущества в установке PreciseTimer
с интервалом 1 мс, поскольку точность таймера на большинстве платформ в любом случае составляет около 1 мс(как объяснено в начале того же параграфа в документации , связанной с ), и установка точности требуется только для более длинных интервалов (я бы сказал, по крайней мере, 25-50 мс).
Здесь также есть интересный ответ о QTimer здесь , объясняющий, что в основном происходит всякий раз, когда вы его создаете, и время его ожидания.