重用 QRunnable

Posted

技术标签:

【中文标题】重用 QRunnable【英文标题】:Re-using QRunnable 【发布时间】:2016-02-22 18:05:27 【问题描述】:

我一直在尝试使用QRunnable,以便启动和运行一些服务调用。我偶然发现了来自Qt documentation 的以下信息:

QThreadPool 支持多次执行同一个 QRunnable 从 QRunnable::run() 中调用 tryStart(this)。如果自动删除是 启用 QRunnable 将在最后一个线程退出时被删除 运行功能。使用相同的 QRunnable 多次调用 start() 当 autoDelete 启用时,会创建一个竞争条件,而不是 推荐。

有人能解释一下这是什么意思吗?我编写了以下代码,它允许我按顺序多次执行QRunnable 对象:

#!/usr/bin/env python

from PyQt4.QtCore import QRunnable, pyqtSlot, pyqtSignal, QObject, QThread, QThreadPool
from PyQt4.QtGui import QApplication, QWidget, QPushButton, QHBoxLayout, QLabel
from sys import exit, argv
from random import getrandbits

class ServiceCallSignals(QObject):
  srv_status = pyqtSignal(bool)
  srv_running = pyqtSignal(bool)

class ServiceCall(QRunnable):

  def __init__(self):
    super(ServiceCall, self).__init__()
    self.signals = ServiceCallSignals()

  def run(self):
    self.signals.srv_running.emit(True)
    call = bool(getrandbits(1))
    print('QRunnable Thread ID: %d' % int(QThread.currentThreadId()))
    if call: QThread.sleep(5)

    self.signals.srv_status.emit(call)
    self.signals.srv_running.emit(False)

class Test(QWidget):

  def __init__(self):
    super(Test, self).__init__()
    self.initUI()

  def initUI(self):

    layout = QHBoxLayout(self)

    self.cb = QPushButton('Send request', self)
    self.cb.clicked.connect(self.srv_send)
    layout.addWidget(self.cb)

    self.lbl = QLabel('Waiting...', self)
    layout.addWidget(self.lbl)

    self.srv = ServiceCall()
    self.srv.setAutoDelete(False)
    self.srv.signals.srv_status.connect(self.srv_receive)
    self.srv.signals.srv_running.connect(self.srv_block)
    self.tp = QThreadPool(self)

    self.setGeometry(300, 300, 250, 150)
    self.setWindowTitle('QRunnable and ROS service calls')
    self.show()

  @pyqtSlot()
  def srv_send(self):
    print('Main Thread ID: %d' % int(QThread.currentThreadId()))
    self.tp.start(self.srv)
    self.cb.setText('Running for reply')

  @pyqtSlot(bool)
  def srv_block(self, state):
    self.cb.setEnabled(not state)

  @pyqtSlot(bool)
  def srv_receive(self, srv_res):
    if srv_res: self.lbl.setText('Success')
    else: self.lbl.setText('Failed')
    self.cb.setText('Send request')

def main():

  app = QApplication(argv)
  t = Test()
  exit(app.exec_())


if __name__ == '__main__':
  main()

文档中的引用是否意味着我做错了?如果我将QThreadPool 并在我的运行中使用tryStart(self),我会运行很多很多线程......

【问题讨论】:

但是你禁用了autoDelete:所以你有什么不明白的? 文档说 tryStart() 应该放在 QRunnablerun() 内,这不是我在这里的做法(请参阅我的帖子的最后一句话,当我放tryStart(self) 在我的run() 中)。 我认为您误解了它 - 请参阅我的回答。 【参考方案1】:

文档说它支持run() 内调用tryStart,而不是必需

如果您在run() 之外按顺序调用start(),它将重新使用同一个线程。但是如果你在run() 中调用tryStart(),它可能会在必要时保留额外的线程。

【讨论】:

啊,我确实误解了文档。谢谢!我很高兴我的代码实际上是正确的。哈哈【参考方案2】:

您需要.setAutoDelete(0) 才能使用trystart()Autodelete(0) 表示线程执行后不会自动删除,需要手动删除。

然后,当使用trystart() 而不是start() 启动/重新启动线程时,会避免竞争条件,因为同一线程会继续。 它在文档上。 祝你好运

【讨论】:

以上是关于重用 QRunnable的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中重用可重用的应用程序

如何使 UIPageViewController 像 tableview 重用单元一样重用控制器?

框架和设计模式的区别

如何使代码可重用? [关闭]

每个唯一的重用标识符是不是都有自己唯一的重用队列?

算法4:合并排序的套路 | 重用 | 分治