我试图用QThread在PyQt6中编写一个多线程程序。
示例代码如下所示。
我使用moveToThread()方法创建了两个线程,并期望在完成后将它们连接起来,但是结果是压倒性的。
我知道另一种方法是创建QThread的子类,编写起来更容易,但我仍然想了解为什么moveToThread()不能这样做。
谢谢!
import sys
import logging
from functools import partial
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
logging.basicConfig(format="%(message)s", level=logging.INFO)
class MyWork(QObject):
finished = pyqtSignal()
def run_work(self, obj_name):
# sleep 3 secs and finish
for i in range(3):
QThread.sleep(1)
logging.info(f'{obj_name}: {i} sec.')
self.finished.emit()
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('MyWork Example')
app = QApplication(sys.argv)
form = MyWindow()
form.show()
# create two threads
th1 = QThread()
wo1 = MyWork()
wo1.moveToThread(th1)
th1.started.connect(partial(wo1.run_work, 'obj1'))
wo1.finished.connect(th1.quit)
th1.start()
th2 = QThread()
wo2 = MyWork()
wo2.moveToThread(th2)
th2.started.connect(partial(wo2.run_work, 'obj2'))
wo2.finished.connect(th2.quit)
th2.start()
# join two threads and finish
th1.wait()
th2.wait()
logging.info('All threads finished.')
sys.exit(app.exec())
产出:
obj1: 0 sec.
obj2: 0 sec.
obj2: 1 sec.
obj1: 1 sec.
obj2: 2 sec.
obj1: 2 sec.
发布于 2022-11-13 16:42:51
你所看到的是由这样一个事实引起的,即跨线程信号在接收器的线程中调用它们连接的函数。
请记住,QThread (就像python中的线程对象一样)不是“线程”,而是访问和运行它的接口。
当你这样做时:
wo1.finished.connect(th1.quit)
结果是,quit()
将在创建th1
的线程中调用,该线程是主线程。
由于wait()
阻塞了调用它的线程的事件循环,所以对quit()
的调用是排队的,从未处理过。
对于这种特殊情况,解决方案是对信号使用直接连接:
wo1.finished.connect(th1.quit, Qt.DirectConnection)
# ...
wo2.finished.connect(th2.quit, Qt.DirectConnection)
通过这样做,将从实际线程调用quit()
,从而允许它立即进行处理。
请注意,您的是一个非常特殊的情况,通常不会被使用。通常,您将工作人员“已完成”信号连接到quit()
和wait()
(按此特定顺序),或者在实际需要退出时按相同顺序调用这些函数,或者将QThread finished
信号连接到最终将打印线程执行完成的函数。
https://stackoverflow.com/questions/74418100
复制相似问题