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) 中行为不端。任何解决方法?

Android 行为不端上的 PhoneGap 选择框

阻止行为不端的用户 facebook sdk ios

PHP / AJAX 并发会话仅在 Chrome 中行为不端

遵循学术规范,避免学术不端