Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-PyQt:QThread内存问题_Python_Multithreading_Pyqt_Pyqt5 - Fatal编程技术网

Python-PyQt:QThread内存问题

Python-PyQt:QThread内存问题,python,multithreading,pyqt,pyqt5,Python,Multithreading,Pyqt,Pyqt5,我想建立一个Qt接口来控制摄像机采集 我想要什么: 在进入硬件通信之前,我正在测试一个GUI,该GUI控制一个“假摄像头”,这是一个连续循环,如果启动,将每100毫秒生成一个随机图像。图像采集在一个单独的线程中运行,以便用户可以与GUI交互。用户可以通过按钮启动和停止采集 我想怎么做: 我的第一次尝试是简单地对QThread进行分析,并调用run()方法,该方法将包含一个无限循环,其中单个图像采集由QThread.sleep(0.1)交错。我注意到在停止并重新启动线程后,程序开始延迟,并在一段时

我想建立一个Qt接口来控制摄像机采集

我想要什么: 在进入硬件通信之前,我正在测试一个GUI,该GUI控制一个“假摄像头”,这是一个连续循环,如果启动,将每100毫秒生成一个随机图像。图像采集在一个单独的线程中运行,以便用户可以与GUI交互。用户可以通过按钮启动和停止采集

我想怎么做: 我的第一次尝试是简单地对
QThread
进行分析,并调用
run()
方法,该方法将包含一个无限循环,其中单个图像采集由
QThread.sleep(0.1)
交错。我注意到在停止并重新启动线程后,程序开始延迟,并在一段时间后崩溃。 通过阅读周围和主要的一些帖子,我了解到做我想做的事情最好的方法是:

子类化a
QObject
以创建辅助对象。实例化此工作人员 对象和一个
QThread
。将辅助线程移动到新线程

此外,按照post中的想法,我添加了一个
QTimer
对象来无限期地迭代线程中的工作线程,并且我实现了一个
active
标志,如果设置为
False
,它只会使线程运行而不做任何事情。 这个解决方案一开始似乎奏效了。我可以任意多次启动、停止和重新启动采集

问题:

1) 当相机没有采集数据时,CPU总是占用相当多的资源(根据windows task menager,在我的例子中大约占30%)

2) 有时,在采集开始后,内存开始被填满,比如如果每个新图像都被分配到新内存中(我猜它应该被覆盖),直到程序变得不负责任,然后崩溃。 下图是发生这种情况时我在task menager中看到的内容: 红色箭头对应采集开始的时间

我哪里做错了?这样做对吗

代码

from PyQt5 import QtCore, QtWidgets
import sys
import numpy as np
import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg


class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('MyWindow')
        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main) 

        # generate matplotlib canvas
        self.fig = matplotlib.figure.Figure(figsize=(4,4))
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.ax = self.fig.add_subplot(1,1,1)
        self.im = self.ax.imshow(np.zeros((1000, 1000)), cmap='viridis')
        self.im.set_clim(vmin=0,vmax=1) 
        self.canvas.draw()

        # Add widgets and build layout
        self.startcambutton = QtWidgets.QPushButton('Start', checkable=True)
        self.startcambutton.released.connect(self.acquire)
        self.contincheck = QtWidgets.QCheckBox("Continuous")
        self.contincheck.clicked.connect(self.continuous_acquisition)
        self.contincheck.setChecked(True)
        layout = QtWidgets.QGridLayout(self._main)
        layout.addWidget(self.canvas, 0, 0)
        layout.addWidget(self.startcambutton, 1, 0)
        layout.addWidget(self.contincheck, 2, 0)

        # Initialize worker and timer and moveToThread
        self.fake_camera_thread = QtCore.QThread()
        self.fake_camera_timer = QtCore.QTimer()
        self.fake_camera_timer.setInterval(0)
        self.fake_camera_worker = FakeCamera(self)
        self.fake_camera_worker.moveToThread(self.fake_camera_thread)
        self.fake_camera_timer.timeout.connect(self.fake_camera_worker.acquire)
        self.fake_camera_thread.started.connect(self.fake_camera_timer.start)
        self.fake_camera_thread.finished.connect(self.fake_camera_worker.deleteLater)
        self.fake_camera_thread.finished.connect(self.fake_camera_timer.deleteLater)
        self.fake_camera_thread.finished.connect(self.fake_camera_thread.deleteLater)
        self.fake_camera_thread.start()

        self.camera_thread = self.fake_camera_thread
        self.camera = self.fake_camera_worker
        self.camera.image.connect(self.image_acquired)

    def continuous_acquisition(self):
        if self.contincheck.isChecked(): self.startcambutton.setCheckable(True)
        else: self.startcambutton.setCheckable(False)

    def acquire(self):
        if self.startcambutton.isCheckable() and not self.startcambutton.isChecked():
            self.startcambutton.setText('Start')
            self.contincheck.setEnabled(True)
        elif self.startcambutton.isCheckable() and self.startcambutton.isChecked():
            self.startcambutton.setText('Stop')
            self.contincheck.setDisabled(True)
        self.camera.toggle()

    @QtCore.pyqtSlot(object)
    def image_acquired(self, image):
        self.im.set_data(image)
        self.canvas.draw()


    def closeEvent(self, event):
        """ If window is closed """
        self.closeApp()
        event.accept() # let the window close

    def closeApp(self):
        """ close program """
        self.camera_thread.quit()
        self.camera_thread.wait()
        self.close()
        return



class FakeCamera(QtCore.QObject):
    image = QtCore.pyqtSignal(object)

    def __init__(self, parent):
        QtCore.QObject.__init__(self)
        self.parent = parent
        self.active = False

    def toggle(self):
        self.active = not self.active

    def acquire(self):
        """ this is the method running indefinitly in the associated thread """
        if self.active:
            self.new_acquisition()

    def new_acquisition(self):
        noise = np.random.normal(0, 1, (1000, 1000))
        self.image.emit(noise)
        if not self.parent.startcambutton.isChecked():
            self.active = False
        QtCore.QThread.sleep(0.1)



if __name__ == '__main__':
    app = QtCore.QCoreApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    mainGui = MyWindow()
    mainGui.show()
    app.aboutToQuit.connect(app.deleteLater)
    app.exec_()
QThread.sleep()
仅接受整个参数,当传递浮点值时,它将对其进行四舍五入,在您的情况下,0.1将四舍五入为0,因此没有暂停,因此信号将连续发出,但绘制需要一段时间,因此数据将存储在队列中,以增加内存。另一方面,如果一个
QTimer
要连续调用一个任务,那么最好在处理该任务的对象的线程中生存,这样就足够让
QTimer
是FakeCamera的儿子了。另一个改进是使用装饰器<代码> @ qtCy.PyQTStULL()/Cudio>因为连接是用C++给出的,所以它更有效。最后,我改进了设计,因为
FakeCamera
不应该直接与GUI交互,因为如果你想与另一个GUI一起使用它,你必须修改很多代码,而最好是创建插槽

from PyQt5 import QtCore, QtWidgets
import numpy as np
import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg


class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('MyWindow')
        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main) 

        # generate matplotlib canvas
        self.fig = matplotlib.figure.Figure(figsize=(4,4))
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.ax = self.fig.add_subplot(1,1,1)
        self.im = self.ax.imshow(np.zeros((1000, 1000)), cmap='viridis')
        self.im.set_clim(vmin=0,vmax=1) 
        self.canvas.draw()

        # Add widgets and build layout
        self.startcambutton = QtWidgets.QPushButton('Start', checkable=True)
        self.startcambutton.released.connect(self.acquire)
        self.contincheck = QtWidgets.QCheckBox("Continuous")
        self.contincheck.toggled.connect(self.startcambutton.setCheckable)
        self.contincheck.setChecked(True)
        layout = QtWidgets.QGridLayout(self._main)
        layout.addWidget(self.canvas, 0, 0)
        layout.addWidget(self.startcambutton, 1, 0)
        layout.addWidget(self.contincheck, 2, 0)

        # Initialize worker and timer and moveToThread
        fake_camera_thread = QtCore.QThread(self)
        self.fake_camera_worker = FakeCamera()
        self.fake_camera_worker.moveToThread(fake_camera_thread)
        self.startcambutton.toggled.connect(self.fake_camera_worker.setState)
        self.fake_camera_worker.image.connect(self.image_acquired)
        fake_camera_thread.started.connect(self.fake_camera_worker.start)
        fake_camera_thread.finished.connect(self.fake_camera_worker.deleteLater)
        fake_camera_thread.finished.connect(fake_camera_thread.deleteLater)
        fake_camera_thread.start()

    @QtCore.pyqtSlot()
    def acquire(self):
        if self.startcambutton.isCheckable():
            text = "Stop" if self.startcambutton.isChecked() else "Start"
            self.startcambutton.setText(text)
            self.contincheck.setEnabled(not self.startcambutton.isChecked())

    @QtCore.pyqtSlot(object)
    def image_acquired(self, image):
        self.im.set_data(image)
        self.canvas.draw()


class FakeCamera(QtCore.QObject):
    image = QtCore.pyqtSignal(object)

    def __init__(self, parent=None):
        super(FakeCamera, self).__init__(parent)
        self.active = False
        self.fake_camera_timer = QtCore.QTimer(self, interval=0)
        self.fake_camera_timer.timeout.connect(self.acquire)

    @QtCore.pyqtSlot()
    def start(self):
        self.fake_camera_timer.start()

    @QtCore.pyqtSlot(bool)
    def setState(self, state):
        self.active = state

    @QtCore.pyqtSlot()
    def toggle(self):
        self.active = not self.active

    @QtCore.pyqtSlot()
    def acquire(self):
        """ this is the method running indefinitly in the associated thread """
        if self.active:
            self.new_acquisition()
        QtCore.QThread.msleep(100)

    def new_acquisition(self):
        noise = np.random.normal(0, 1, (1000, 1000))
        self.image.emit(noise)


if __name__ == '__main__':
    import sys
    app = QtCore.QCoreApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    mainGui = MyWindow()
    mainGui.show()
    app.aboutToQuit.connect(app.deleteLater)
    sys.exit(app.exec_())

谢谢你的建议。像往常一样,变化是有益的!