从继承的QThread迁移到Worker mod

2024-06-26 14:02:33 发布

您现在位置:Python中文网/ 问答频道 /正文

所以在我之前的问题中通过了很多帮助 (Interrupting QThread sleep 并且PySide passing signals from QThread to a slot in another QThread)我决定尝试从继承的QThread模型更改为Worker模型。我在想我应该继续使用QThread模型,因为我已经有了它的工作,而另一个模型没有。然而,我不知道为什么工人模式不适合我。在

我正在尝试这样做请让我知道,如果我的方法有什么固有的错误?在

我有一个QtGui.QWidget这是我的主GUI。我用QPushButton来发信号 我试图将代码简化为我认为问题所在的基本情况。我已经验证了datagramHandledSignal被发出,但是packet_handledSlot似乎没有被调用。在

class myObject(QtCore.QObject):
    def __init__(self):
        super(myObject, self).__init__()
        self.ready=False

    @QtCore.Slot()
    def do_work(self):
        #send a packet
        self.ready=False
        while not self.ready:
            time.sleep(0.01)

    @QtCore.Slot(int)
    def packet_handled(self, errorCode):
        print "Packet received."
        self.ready = True

class myWidget(QtGui.QWidget):
    datagramHandled = QtCore.Signal(int)
    startRunThread = QtCore.Signal()
    def __init__(self,parent=None, **kwargs):
        super(myWidget, self).__init__(parent=parent)
        # Bunch of GUI setup stuff (working)
        self.myRunThread = QtCore.QThread()
    @QtCore.Slot()
    def run_command(self):
        self.myRunObj = myObject()
        self.myRunObj.moveToThread(self.myRunThread)
        self.datagramHandled.connect(self.myRunObj.packet_handled)
        self.startRunThread.connect(self.myRunObj.do_work)
        self.myRunThread.start()
        self.startRunThread.emit()

    @QtCore.Slot()
    def handle_datagram(self):
        #handle the incoming datagram
        errorCode = 0
        self.datagramHandled.emit(errorCode)

Tags: 模型selfpacketinitdefparentslotready
3条回答

使用Qt分配计算/其他负载有三种可能的方法:

  1. 显式地将负载放入具体的QThread实例。即基于线程的并发性。在
  2. 隐式地将负载放入池QThread实例。这更接近于基于任务的并发,但使用您自己的逻辑进行“手动”管理。QThreadPool类用于维护线程池。在
  3. 在自己的线程上下文中启动任务我们从来没有显式地管理。这是使用的基于任务的并发和QtConcurrent命名空间。我的猜测是基于任务的并发性和“工作者模型”是同一回事(观察到了您的变化)。请注意,QtConcurrent确实为任务提供了并行化,并使用了异常(这可能会影响您编写代码的方式),这与Qt的其他部分不同。在

如果使用PyQt,还可以利用为要用QtConcurrent for PyQt实现的模式指定的特性。在

另外,我看到使用thread.sleep( interval ),这不是一个好的实践,这又一个迹象表明,应该使用适当的技术来实现“工人模型”。在

@JonHarper提供的解决方案的另一种方法是用QTimer替换while循环。因为现在在工作进程中运行了一个事件循环,它可以正确地处理QTimer事件(只要在相关线程中构造QTimer)。在

这样,控制会定期返回到事件循环,以便在需要时可以运行其他插槽。在

第一个问题是需要将myObject.do_work方法连接到QThread.started

self.myRunThread.started.connect(self.myRunObj.do_work)

第二,您的do_work方法应该包括以下几行内容,以启用事件处理(请原谅我生疏的PyQt和伪代码):

^{pr2}$

有关更多信息,请查看^{}的文档。在

这里的逻辑是,当一个信号从一个线程(myWidget.datagramHandled)发出时,它将在工作线程的事件循环中排队。调用processEvents处理任何挂起的事件(包括排队信号,实际上只是事件),为任何排队的信号调用适当的时隙(myRunObj.packet_handled)。在

进一步阅读:

相关问题 更多 >