gpt4 book ai didi

python - time.sleep() 需要保持 QThread 响应吗?

转载 作者:太空宇宙 更新时间:2023-11-04 01:29:50 33 4
gpt4 key购买 nike

首先,我是 Python 新手。我是 MatLab 的长期用户(工程师,而不是计算机科学家),我正在开始尝试将 Python、NumPy、SciPy 等应用到我的工作流程中。所以,请原谅我对什么是美妙的编程语言的明显无知!

作为我的第一个尝试,我决定构建一个应用程序来与我正在开发的传感器进行交互。传感器具有微秒分辨率(每 500 微秒来自 512 个高能量和 512 个低能量“像素”的数据),但 I/O 将被阻塞。因为我会不断地轮询设备,所以我知道线程对于保持 GUI 响应很重要(GUI 最终还将集成与另一个设备的串行通信,并具有一个对传感器数据进行操作的图像处理子例程)。我创建了一个 MatPlotLib 的线程实例来绘制来自传感器的这些“实时”数据。虽然我已经构建了独立与传感器通信的模块并验证了我知道如何在 Python 中执行此操作,但我在这里只是通过为低能量生成 8 到 12 之间的 512 个随机数来“模拟”数据“像素”,以及用于高能量“像素”的 90 到 110 之间的 512 个随机数。这就是线程。从这里的许多示例中,我还学会了使用 blitting 来通过 MatPlotLib 获得足够快的屏幕更新——但是,问题是除非我使用 time.sleep(0.02) 让线程进程休眠 20ms ,GUI 没有响应。这可以得到验证,因为来自 MatPlotLib 的交互式 X、Y 数据点反馈不起作用,并且不能使用“停止”按钮来中断该过程。任何比 time.sleep(0.02) 更长的时间都会使 GUI 操作更加流畅,但会以“数据速率”为代价。任何比 time.sleep(0.02) 慢的东西都会使 GUI 无响应。我不确定我明白为什么。我打算离开并尝试改用 GUIqwt,但我想在放弃 MatPlotLib 之前我会在这里问,因为我不确定这甚至是问题所在。我担心让线程休眠 20 毫秒将意味着我会错过至少 40 行来自传感器阵列的潜在数据(40 行 * 500us/行 = 20 毫秒)。

这是当前代码:

import time, random, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

class ApplicationWindow(QMainWindow):

def __init__(self, parent = None):

QMainWindow.__init__(self, parent)

self.thread = Worker()

self.create_main_frame()
self.create_status_bar()

self.connect(self.thread, SIGNAL("finished()"), self.update_UI)
self.connect(self.thread, SIGNAL("terminated()"), self.update_UI)
self.connect(self.startButton, SIGNAL("clicked()"), self.start_acquisition)
self.connect(self.stopButton, SIGNAL("clicked()"), self.stop_acquisition)
self.thread.pixel_list.connect(self.update_figure)

def create_main_frame(self):
self.main_frame = QWidget()

self.dpi = 100
self.width = 10
self.height = 8
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,120))

self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.canvas.draw()
self.background = None

self.lE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)
self.hE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)

self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

self.startButton = QPushButton(self.tr("&Start"))
self.stopButton = QPushButton(self.tr("&Stop"))

layout = QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.mpl_toolbar, 1, 0)
layout.addWidget(self.startButton, 2, 0)
layout.addWidget(self.stopButton, 2, 1)

self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)

self.setWindowTitle(self.tr("XRTdev Interface"))

def create_status_bar(self):
self.status_text = QLabel("I am a status bar. I need a status to show!")
self.statusBar().addWidget(self.status_text, 1)

def start_acquisition(self):
self.thread.exiting = False
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.thread.render()

def stop_acquisition(self):
self.thread.exiting = True
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()

def update_figure(self, lE, hE):
if self.background == None:
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.canvas.restore_region(self.background)
self.lE_line.set_ydata(lE)
self.hE_line.set_ydata(hE)
self.axes.draw_artist(self.lE_line)
self.axes.draw_artist(self.hE_line)
self.canvas.blit(self.axes.bbox)

def update_UI(self):
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()

def cleanup_UI(self):
self.background = None
self.axes.clear()
self.canvas.draw()

class Worker(QThread):

pixel_list = pyqtSignal(list, list)

def __init__(self, parent = None):
QThread.__init__(self, parent)
self.exiting = False

def __del__(self):
self.exiting = True
self.wait()

def render(self):
self.start()

def run(self):
# simulate I/O
n = random.randrange(100,200)
while not self.exiting and n > 0:
lE = [random.randrange(5,16) for i in xrange(512)]
hE = [random.randrange(80,121) for i in xrange(512)]
self.pixel_list.emit(lE, hE)
time.sleep(0.02)
n -= 1

def main():
app = QApplication(sys.argv)
form = ApplicationWindow()
form.show()
app.exec_()

if __name__ == "__main__":
main()

也许我的问题甚至不在于 MatPlotLib 或 PyQT4,而是我实现线程的方式。正如我所指出的,我对此并不陌生并且正在学习。而且,我什至不确定 GUIqwt 是否会解决这些问题中的任何一个——但我知道我在这里看到了很多建议使用比 MatPlotLib 更快的东西在 GUI 中进行“实时”绘图。感谢您对此的帮助!

最佳答案

[编辑因为 QThread 令人困惑/困惑]

似乎有两种使用它的方法,要么对其进行子类化(如您的示例和文档所述),要么创建一个工作对象,然后将其移动到一个线程(参见 this blog post)。当你混合信号/插槽时,我会变得更加困惑。正如 Avaris 所说,这种变化可能不是你的问题。

我将您的 Worker 类重新设计为 QObject 的子类(因为这是我理解的样式)。

一个问题是,如果你不在你的假数据系统中放置一个 sleep,那么你会在 < 1 秒内生成对主窗口的所有回调。然后主线程在清除信号队列时基本上被阻塞。如果您将延迟设置为您指定的延迟(0.0005 秒),那么它会以比显示数据快得多的速度生成数据,这似乎表明这可能不适合您的问题(务实,您也可以没那么快,而且似乎在 30 - 40 fps 时还可以)。

import time, random, sys
#from PySide.QtCore import *
#from PySide.QtGui import *

from PyQt4 import QtCore
from PyQt4 import QtGui

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

class ApplicationWindow(QtGui.QMainWindow):
get_data = QtCore.pyqtSignal()

def __init__(self, parent = None):

QtGui.QMainWindow.__init__(self, parent)


self.thread = QtCore.QThread(parent=self)
self.worker = Worker(parent=None)
self.worker.moveToThread(self.thread)

self.create_main_frame()
self.create_status_bar()

self.startButton.clicked.connect(self.start_acquisition)
self.stopButton.clicked.connect(self.stop_acquisition)
self.worker.pixel_list.connect(self.update_figure)
self.worker.done.connect(self.update_UI)

self.get_data.connect(self.worker.get_data)


self.thread.start()


def create_main_frame(self):
self.main_frame = QtGui.QWidget()

self.dpi = 100
self.width = 10
self.height = 8
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,120))

self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.canvas.draw()
self.background = None

self.lE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)
self.hE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)

self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

self.startButton = QtGui.QPushButton(self.tr("&Start"))
self.stopButton = QtGui.QPushButton(self.tr("&Stop"))

layout = QtGui.QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.mpl_toolbar, 1, 0)
layout.addWidget(self.startButton, 2, 0)
layout.addWidget(self.stopButton, 2, 1)

self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)

self.setWindowTitle(self.tr("XRTdev Interface"))

def create_status_bar(self):
self.status_text = QtGui.QLabel("I am a status bar. I need a status to show!")
self.statusBar().addWidget(self.status_text, 1)

def start_acquisition(self):
self.worker.exiting = False
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.get_data.emit()

def stop_acquisition(self):
self.worker.exiting = True
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()

def update_figure(self, lE, hE):
if self.background == None:
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.canvas.restore_region(self.background)
self.lE_line.set_ydata(lE)
self.hE_line.set_ydata(hE)
self.axes.draw_artist(self.lE_line)
self.axes.draw_artist(self.hE_line)
self.canvas.blit(self.axes.bbox)

def update_UI(self):
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()

def cleanup_UI(self):
self.background = None
self.axes.clear()
self.canvas.draw()

class Worker(QtCore.QObject):

pixel_list = QtCore.pyqtSignal(list, list)
done = QtCore.pyqtSignal()

def __init__(self, parent = None):
QtCore.QObject.__init__(self, parent)
self.exiting = True

@QtCore.pyqtSlot()
def get_data(self):
# simulate I/O
print 'data_start'
n = random.randrange(100,200)
while not self.exiting and n > 0:
lE = [random.randrange(5,16) for i in xrange(512)]
hE = [random.randrange(80,121) for i in xrange(512)]
self.pixel_list.emit(lE, hE)
time.sleep(0.05)
n -= 1
print 'n: ', n
self.done.emit()

关于python - time.sleep() 需要保持 QThread 响应吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14665636/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com