在工人类被moveToThread
之后,我在制作插槽接收信号时遇到了问题。目标是在另一个线程上执行工作线程中的槽。
这是我的测试工人班:
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()
信号需要事件循环才能工作,在您的情况下,您必须创建一个QCoreApplication:
def moveToThreadTest():
app = QCoreApplication.instance()
if app is None:
app = QCoreApplication()
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...")
app.exec_()
将threading.get_ident()
更改为threading.current_thread()
,即可获得
INFO:140406642902848: main started...
INFO:<_MainThread(MainThread, started 140406642902848)>: DbWorker instantiated...
INFO:140406642902848: main thread end...
INFO:<_DummyThread(Dummy-1, started daemon 140406565365312)>: Process slot activated!
INFO:<_DummyThread(Dummy-1, started daemon 140406565365312)>: test_slot_str fired. Got Message 'test'
INFO:<_DummyThread(Dummy-1, started daemon 140406565365312)>: test_slot_empty fire
在最初的情况下(部分工作(,碰巧有时间创建线程,但由于函数立即终止,因此对象也被销毁。