QThreadPool中的行为不端QSignals,QRunnable在python中使用QThead
Posted
技术标签:
【中文标题】QThreadPool中的行为不端QSignals,QRunnable在python中使用QThead【英文标题】:Misbehaving QSignals in QThreadPool, QRunnable using QThead on top of it in python 【发布时间】:2014-11-15 09:52:08 【问题描述】:我陷入了一种情况,即我的前几个信号通过,后来没有信号发出。
我会详细阐述:
我的工作需要繁重的处理和内存,并且可能需要 2-4 小时才能完成它而无需以线性方式进行线程处理,因此我决定使用 QTheadPool,因此我创建(在测试时)355 个 QRunners 开始由 QThreadPool 提供。其中很少有人(QRunners)依赖于另一个 QRunners 来完成。一切正常,我能够通过发出信号并捕获它们来推导依赖关系。当我在没有 GUI 的情况下运行它时,它的一切工作绝对完美
例如(以下代码未经测试,我只是在这里输入):
from PyQt4 import QtCore
class StreamPool(QtCore.QObject):
def __init__(self, inputs, q_app):
super(....)
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def start(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
def mark_as_start(self, name):
print 'operation started..', name
# Some operation...
def mark_as_finish(self, name):
print 'operation finished..', name
# Some operation...
class StreamRunner(QtCore.QRunnable):
def __init__(self, input, q_app):
super(..)
self.input = input
self.q_app = q_app
self.signal = WorkSignals()
def run(self):
self.signal.operation_started.emit(input)
self.q_ap
# Doing some operations
self.signal.operation_finished.emit(input)
self.q_app.processEvents()
class WorkSignals(QtCore.QObject):
operation_started = QtCore.pyqtSignal(str)
operation_finished= QtCore.pyqtSignal(str)
if __name__ == '__main__':
app = QtGui.QApplication([])
st = StreamPool(['a', 'b', 'c'], app)
st.start()
app.exec_()
在上述情况下效果很好。
我想在 ui 中显示状态,因为可以执行数百个任务,所以我编写了一个简单的 ui,并从另一个 QThread 运行 StreamPool() 可以说命名为 - StreamWorkThread(),它由ui 和 StreamWorkThread 捕获 StreamPool.signal.* 并将它们发送回 ui,但在这种情况下,StreamPool 只能发出其中的少数,开始的 4 或 5,尽管任务仍在执行但相关任务没有得到初始化由于这种行为,用户界面中不会显示任何状态更新。
我不能和你们分享代码,因为它来自我的工作场所,我可以在这里写类似的方法
class StreamWorkThread (QtCore.QThread):
def __init__(self, inputs, q_app):
super(..)
self.signal = WorkSignals()
self.stream_pool = StreamPool(inputs, q_app)self.stream_pool.signal.operation_started.connect(self.signal.operation_started.emit)
self.stream_pool.signal.operation_finished.connect(self.signal.operation_finished.emit)
def run(self):
self.stream_pool.start()
def print_start(name):
print 'Started --', name
def print_finished(name):
print 'Finished --', name
if __name__ == '__main__':
app = QtGui.QApplication([])
th = StreamWorkThread (['a', 'b', 'c'], app)
th.signal.operation_started.connect(print_start)
th.signal.operation_finshed.connect(print_finished)
th.start()
app.exec_()
合并代码:
from PyQt4 import QtCore
class StreamPool(QtCore.QObject):
def __inti__(self, inputs, q_app):
super(StreamPool, self).__init()
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def start(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
def mark_as_start(self, name):
print 'operation started..', name
# Some operation...
def mark_as_finish(self, name):
print 'operation finished..', name
# Some operation...
class StreamRunner(QtCore.QRunnable):
def __init__(self, input, q_app):
super(StreamRunner, self).__init()
self.input = input
self.q_app = q_app
self.signal = WorkSignals()
def run(self):
self.signal.operation_started.emit(input)
self.q_ap
# Doing some operations
self.signal.operation_finished.emit(input)
self.q_app.processEvents()
class WorkSignals(QtCore.QObject):
operation_started = QtCore.pyqtSignal(str)
operation_finished= QtCore.pyqtSignal(str)
class StreamWorkThread (QtCore.QThread):
def __init__(self, inputs, q_app):
super(StreamWorkThread, self).__init()
self.signal = WorkSignals()
self.stream_pool = StreamPool(inputs,q_app)
self.stream_pool.signal.operation_started.connect(self.signal.operation_started.emit)
self.stream_pool.signal.operation_finished.connect(self.signal.operation_finished.emit)
def run(self):
self.stream_pool.start()
def print_start(name):
print 'Started --', name
def print_finished(name):
print 'Finished --', name
if __name__ == '__main__':
app = QtGui.QApplication([])
th = StreamWorkThread (['a', 'b', 'c'], app)
th.signal.operation_started.connect(print_start)
th.signal.operation_finshed.connect(print_finished)
th.start()
app.exec_()
请大家帮帮我,我不明白这里到底是什么问题..! :(
【问题讨论】:
【参考方案1】:好的,我找到了解决此问题的方法。
阻塞信号的根本原因是继承了 StrealPool 中的 QObject
,当我将 QObject 替换为 QThread
时,它可以无缝工作。
这是我所做的更改,只有两个地方
class StreamPool(**QtCore.QThread**):
def __inti__(self, inputs, q_app):
super(StreamPool, self).__init()
self.inputs = inputs
self.q_app = q_app
self.pool = QtCore.QThreadPool()
def **run**(self):
for each_input in self.inputs:
runner = StreamRunner(each_input, self.q_app)
runner.signal.operation_started.connect(self.mark_as_start)
runner.signal.operation_finished.connect(self.mark_as_start)
self.pool.start(runner)
那一套,它奏效了! :D
【讨论】:
【参考方案2】:没有源代码非常困难,但问题可能是当“app.exec_()”运行时,gui的主循环启动并干扰您的Streamx类
【讨论】:
感谢@Ludovic 的快速响应,但在这里即使我没有调用 ui 而只是调用 StreamWorkThread 它也不会工作。尽管发出了前几个信号。您还有其他建议吗? 如果我在 StreamPool().start() 方法的末尾添加 self.pool.waitForDone() ,我还想指出一件事,我能够接收所有信号,但在在操作的最后,这样我的用户界面不会有实时状态更新所有状态将立即更新 尝试覆盖StreamWorkThread的默认析构函数(方法名为__del__
)并打印一些东西看它是否被垃圾回收,你也可以在析构函数中执行self.wait()
尝试覆盖 __del__
添加打印语句和 self.wait()
即使我使用 waitForDone()
或它没有击中 __del__
。
什么是 QRunner ?是 QRunnable 吗?您是否尝试过标准库中的线程模块?以上是关于QThreadPool中的行为不端QSignals,QRunnable在python中使用QThead的主要内容,如果未能解决你的问题,请参考以下文章
iOS 中的 MIDI 合成行为不端 WRT 弯音:忽略 LSB
QT 中的 QSlider 在新的 MacOS Monterey (v12.0.1) 中行为不端。任何解决方法?