gpt4 book ai didi

PyQt |不在 QThread 中处理但在主线程中处理的信号

转载 作者:行者123 更新时间:2023-12-04 22:46:29 25 4
gpt4 key购买 nike

在这个简单的 PyQt 演示程序中,我从主线程发出信号。在工作线程中,我连接到它们,但信号处理程序在主线程中运行:

from PyQt4 import QtGui, QtCore
import threading
from time import sleep
import sys


class Data():
def __init__(self, a, b):
self.a = a
self.b = b

def __str__(self):
return "Data having %d and %d" % (self.a, self.b)

class Worker(QtCore.QThread):
def __init__(self, parent):
QtCore.QThread.__init__(self)
self.p = parent

def run(self):
self.connect(self.p, QtCore.SIGNAL("newTask"), self.task)
print "[%s] running exec_()" % threading.currentThread()
self.exec_()

def task(self, dataobj):
print "[%s] Processing" % threading.currentThread(), dataobj
sleep(3)
print "Done with", dataobj
self.emit(QtCore.SIGNAL("taskDone"), str(dataobj))

class App(QtCore.QObject):
def __init__(self):
QtCore.QObject.__init__(self)
self.w = Worker(self)
self.connect(self.w, QtCore.SIGNAL("taskDone"), self.on_task_done)
self.w.start()

def assign_tasks(self):
self.emit(QtCore.SIGNAL("newTask"), Data(3, 4))
self.emit(QtCore.SIGNAL("newTask"), Data(5, 6))
print "[%s] Tasks sent" % threading.currentThread()

@staticmethod
def on_task_done(objstr):
print "[%s] App: Worker finished with" % threading.currentThread(), objstr

if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
a = App()
sleep(1)
a.assign_tasks()
sleep(20)
sys.exit(app.exec_())

但结果显示回调是在主线程中运行的:
[<_DummyThread(Dummy-1, started daemon 105564)>] running exec_()
[<_MainThread(MainThread, started 105612)>] Processing Data having 3 and 4
Done with Data having 3 and 4
[<_MainThread(MainThread, started 105612)>] App: Worker finished with Data having 3 and 4
[<_MainThread(MainThread, started 105612)>] Processing Data having 5 and 6
Done with Data having 5 and 6
[<_MainThread(MainThread, started 105612)>] App: Worker finished with Data having 5 and 6
[<_MainThread(MainThread, started 105612)>] Tasks sent

我究竟做错了什么?不幸的是,关于此的 PyQt 文档非常不完整且相互矛盾。

如果我使用 moveToThread,我会得到类似的结果技术:
from PyQt4 import QtGui, QtCore
import threading
from time import sleep
import sys

class Data():
def __init__(self, a, b):
self.a = a
self.b = b

def __str__(self):
return "Data having %d and %d" % (self.a, self.b)

class Worker(QtCore.QObject):
def __init__(self, parent):
QtCore.QObject.__init__(self)
self.connect(parent, QtCore.SIGNAL("newTask"), self.task)

def task(self, dataobj):
print "[%s] Processing" % threading.currentThread(), dataobj
sleep(3)
print "Done with", dataobj
self.emit(QtCore.SIGNAL("taskDone"), str(dataobj))

def start(self):
print "[%s] start()" % threading.currentThread()

class App(QtCore.QObject):
def __init__(self):
QtCore.QObject.__init__(self)

self.w = Worker(self)
self.t = QtCore.QThread(self)
self.w.moveToThread(self.t)
self.connect(self.w, QtCore.SIGNAL("taskDone"), self.on_task_done)
self.connect(self.t, QtCore.SIGNAL("started()"), self.w.start)
self.t.start()

def assign_tasks(self):
self.emit(QtCore.SIGNAL("newTask"), Data(3, 4))
self.emit(QtCore.SIGNAL("newTask"), Data(5, 6))
print "[%s] Tasks sent" % threading.currentThread()

@staticmethod
def on_task_done(objstr):
print "[%s] App: Worker finished with" % threading.currentThread(), objstr

if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
a = App()
sleep(1)
a.assign_tasks()
sleep(20)
sys.exit(app.exec_())

结果是:
[<_DummyThread(Dummy-1, started daemon 108992)>] start()
[<_MainThread(MainThread, started 107004)>] Processing Data having 3 and 4
Done with Data having 3 and 4
[<_MainThread(MainThread, started 107004)>] App: Worker finished with Data having 3 and 4
[<_MainThread(MainThread, started 107004)>] Processing Data having 5 and 6
Done with Data having 5 and 6
[<_MainThread(MainThread, started 107004)>] App: Worker finished with Data having 5 and 6
[<_MainThread(MainThread, started 107004)>] Tasks sent

最佳答案

您的 Worker对象“存活”在主线程中,这意味着它们的所有信号都将由主线程的事件循环处理。事实上,这些对象是 QThread s 不会改变这一点。

如果您希望信号由不同的线程处理,您首先需要使用它的 moveToThread 将工作对象移动到该线程。方法。

所以在你的情况下,只有 run方法实际上是在不同的线程中执行的,task方法仍然在主线程中执行。改变这种情况的一种方法是:

  • 让您的 Worker普通 QObject ,不是 QThread
  • 创建 QThread在您的 App ,启动它并将工作线程移动到该线程
  • 然后将信号发送给工作人员,使其开始处理

  • 您应该查看这些引用资料:
  • QObject thread affinity
  • Qt threading basics
  • Multithreading technologies in Qt


  • 编辑:

    我在您的代码中注意到的其他一些事情:
  • 您正在混合使用 python 线程和 qt 线程。 threading.currentThread不会正确反射(reflect)当前的 qt 线程。使用 QThread.currentThread()为了那个原因。
  • 将您调用的插槽装饰为 pyqtSlots ,不这样做可能会导致此类问题。
  • 使用 new style signals . PyQt5 不再支持旧式信号,新式信号更容易使用。

  • 所以这是你的代码应该可以工作的一个版本:
    from PyQt4 import QtGui, QtCore
    import threading
    from time import sleep
    import sys

    class Data():
    def __init__(self, a, b):
    self.a = a
    self.b = b

    def __str__(self):
    return "Data having %d and %d" % (self.a, self.b)

    class Worker(QtCore.QObject):

    taskDone = QtCore.pyqtSignal(str)

    def __init__(self, parent):
    QtCore.QObject.__init__(self)
    parent.newTask.connect(self.task)

    @QtCore.pyqtSlot(object)
    def task(self, dataobj):
    print "[%s] Processing" % QtCore.QThread.currentThread().objectName(), dataobj
    sleep(3)
    print "Done with", dataobj
    self.taskDone.emit(str(dataobj))

    @QtCore.pyqtSlot()
    def start(self):
    print "[%s] start()" % QtCore.QThread.currentThread().objectName()

    class App(QtCore.QObject):

    newTask = QtCore.pyqtSignal(object)

    def __init__(self):
    QtCore.QObject.__init__(self)
    self.w = Worker(self)
    self.t = QtCore.QThread(self, objectName='workerThread')
    self.w.moveToThread(self.t)
    self.w.taskDone.connect(self.on_task_done)
    self.t.started.connect(self.w.start)
    self.t.start()

    def assign_tasks(self):
    self.newTask.emit(Data(3, 4))
    self.newTask.emit(Data(5, 6))
    print "[%s] Tasks sent" % QtCore.QThread.currentThread().objectName()

    @staticmethod
    def on_task_done(objstr):
    print "[%s] App: Worker finished with" % QtCore.QThread.currentThread().objectName(), objstr

    if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    QtCore.QThread.currentThread().setObjectName('main')
    a = App()
    sleep(1)
    a.assign_tasks()
    from utils import sigint
    sys.exit(app.exec_())

    我已经设置了线程的 objectName s 使输出更具可读性:

    [workerThread] 开始()
    [主要] 发送的任务
    [workerThread] 处理具有 3 和 4 的数据
    完成具有 3 和 4 的数据
    [workerThread] 处理具有 5 和 6 的数据
    [main] App: Worker 完成了具有 3 和 4 的数据
    完成具有 5 和 6 的数据
    [main] 应用程序:Worker 完成了具有 5 和 6 的数据

    关于PyQt |不在 QThread 中处理但在主线程中处理的信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23718761/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com