【发布时间】:2021-12-26 12:27:39
【问题描述】:
在工人阶级成为moveToThread 后,我无法让插槽接收信号。
目标是worker内部的slots将在另一个线程上执行。
这是我的测试工作者类:
class DbWorker(QObject):
def __init__(self):
super().__init__()
logger.info(f"{threading.get_ident()}: DbWorker instantiated...")
@Slot(str)
def test_slot_str(self, test_text: str):
logger.info(f"{threading.get_ident()}: test_slot_str fired. Got Message '{test_text}'")
@Slot()
def test_slot_empty(self):
logger.info(f"{threading.get_ident()}: test_slot_empty fired ")
@Slot()
def process(self):
logger.info(f"{threading.get_ident()}: Process slot activated!")
当我执行这个时:
# Signals must inherit QObject
class Communicate(QObject):
signal_str = Signal(str)
signal_empty = Signal()
def moveToThreadTest():
logger.info(f"{threading.get_ident()}: main started...")
worker = DbWorker()
communicate = Communicate()
my_thread = QThread()
worker.moveToThread(my_thread)
communicate.signal_str.connect(worker.test_slot_str)
communicate.signal_empty.connect(worker.test_slot_empty)
my_thread.started.connect(worker.process)
my_thread.start()
communicate.signal_str.emit("test")
communicate.signal_empty.emit()
logger.info(f"{threading.get_ident()}: main thread end...")
我得到的输出是输出:
- INFO [db_worker.py:35 - moveToThreadTest() ] 13824: main started...
- INFO [db_worker.py:12 - __init__() ] 13824: DbWorker instantiated...
- INFO [db_worker.py:48 - moveToThreadTest() ] 13824: main thread end...
- INFO [db_worker.py:25 - process() ] 20776: Process slot activated!
所以连接到my_thread.started 的槽设法从另一个线程执行。但是其他插槽都没有这样做。此外,值得指出的是,仅当我在没有调试的情况下运行此代码时才会打印最后一行。如果我在调试模式下运行,我会得到:
- INFO [db_worker.py:35 - moveToThreadTest() ] 25128: main started...
- INFO [db_worker.py:12 - __init__() ] 25128: DbWorker instantiated...
- INFO [db_worker.py:48 - moveToThreadTest() ] 25128: main thread end...
我尝试查看是否以正确的方式将信号连接到插槽,因此我运行了相同的示例,而没有将工作线程移动到这样的线程:
def withoutMoveToThread():
logger.info(f"{threading.get_ident()}: main started...")
communicate = Communicate()
worker = DbWorker()
communicate.signal_str.connect(worker.test_slot_str)
communicate.signal_empty.connect(worker.test_slot_empty)
communicate.signal_str.emit("Signal str")
communicate.signal_empty.emit()
logger.info(f"{threading.get_ident()}: main finished...")
而且它似乎工作得很好:
- INFO [db_worker.py:52 - withoutMoveToThread() ] 6052: main started...
- INFO [db_worker.py:12 - __init__() ] 6052: DbWorker instantiated...
- INFO [db_worker.py:16 - test_slot_str() ] 6052: test_slot_str fired. Got Message 'Signal str'
- INFO [db_worker.py:20 - test_slot_empty() ] 6052: test_slot_empty fired
- INFO [db_worker.py:59 - withoutMoveToThread() ] 6052: main finished...
我不明白我做错了什么以及为什么我的插槽没有接收到连接的信号。请帮助我理解我做错了什么。
这是完整的示例文件:
import threading
from PySide2 import QtCore
from PySide2.QtCore import QObject, Slot, Signal, QThread
from logger import logger
class DbWorker(QObject):
def __init__(self):
super().__init__()
logger.info(f"{threading.get_ident()}: DbWorker instantiated...")
@Slot(str)
def test_slot_str(self, test_text: str):
logger.info(f"{threading.get_ident()}: test_slot_str fired. Got Message '{test_text}'")
@Slot()
def test_slot_empty(self):
logger.info(f"{threading.get_ident()}: test_slot_empty fired ")
@Slot()
def process(self):
# print("Process Activated!")
logger.info(f"{threading.get_ident()}: Process slot activated!")
# Signals must inherit QObject
class Communicate(QObject):
signal_str = Signal(str)
signal_empty = Signal()
def moveToThreadTest():
logger.info(f"{threading.get_ident()}: main started...")
worker = DbWorker()
communicate = Communicate()
my_thread = QThread()
worker.moveToThread(my_thread)
communicate.signal_str.connect(worker.test_slot_str)
communicate.signal_empty.connect(worker.test_slot_empty)
my_thread.started.connect(worker.process)
my_thread.start()
communicate.signal_str.emit("test")
communicate.signal_empty.emit()
logger.info(f"{threading.get_ident()}: main thread end...")
def withoutMoveToThread():
logger.info(f"{threading.get_ident()}: main started...")
communicate = Communicate()
worker = DbWorker()
communicate.signal_str.connect(worker.test_slot_str)
communicate.signal_empty.connect(worker.test_slot_empty)
communicate.signal_str.emit("Signal str")
communicate.signal_empty.emit()
logger.info(f"{threading.get_ident()}: main finished...")
if __name__ == '__main__':
withoutMoveToThread()
【问题讨论】:
-
withoutMoveToThread“工作”只是因为连接是直接,它导致直接调用连接的插槽。在您的另一个示例中,有两个问题:您没有创建 QCoreApplication (也没有运行它的事件循环),并且在该函数中创建的所有对象一旦返回就会被垃圾收集。