簡體   English   中英

工作人員完成后不發出 QThread.finished 信號

[英]QThread.finished signal isn't emitted after worker finishes

我有以下代碼:

import time

from PyQt5.QtCore import QThread, QObject
from PyQt5.QtWidgets import QWidget, QApplication


class Worker(QObject):

    def run(self):
        time.sleep(1)
        print("Worker is finished")


class MainWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.show()

        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.thread.finished.connect(self.on_thread_finished)
        self.thread.start()

    def on_thread_finished(self):
        print("Thread finished")
        self.thread.deleteLater()


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    app.exec_()

運行它,它顯示窗口,打印Worker is finished ,僅此而已。 這很奇怪。 恕我直言,當工人完成時,線程也應該完成,這意味着應該調用on_thread_finished方法並打印Thread finished 但事實並非如此。 為什么?

當您使用moveToThread而不是重新實現QThread.run時,線程將啟動自己的事件循環,該循環將等待直到顯式調用exit/quit finished信號僅在事件循環停止后(和/或run返回)發出。 處理這種情況的常用方法是從 worker 發出自定義信號,並將其連接到線程的quit槽。 (注意:跨線程信號槽連接保證是線程安全的)。

因此,您的示例將通過以下更改按預期工作:

class Worker(QObject):
    finished = QtCore.pyqtSignal()

    def run(self):
        time.sleep(1)
        print("Worker is finished")
        self.finished.emit()


class MainWindow(QWidget):    
    def __init__(self):
        ...
        self.worker.moveToThread(self.thread)
        self.worker.finished.connect(self.thread.quit)

當工人完成時,線程也應該完成

這不是它的工作原理。 您的Worker::run方法通過通常的signal / slot機制作為slot調用,之后QThread將繼續正常處理事件。

如果你想在Worker::run完成時終止QThread ,你需要明確告訴它這樣做......

import time

from PyQt5.QtCore import Qt, QThread, QObject
from PyQt5.QtWidgets import QWidget, QApplication


class Worker(QObject):

    # Constructor accepts the QThread as a parameter and stashes it
    # for later use.
    def __init__(self, thread):
        super(Worker, self).__init__()
        self.m_thread = thread
    def run(self):
        time.sleep(1)
        print("Worker is finished")

        # We're done so ask the `QThread` to terminate.
        if self.m_thread:
            self.m_thread.quit()


class MainWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.show()

        self.thread = QThread()

        # Pass the QThread to the Worker's ctor.
        self.worker = Worker(self.thread)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.thread.finished.connect(self.on_thread_finished)
        self.thread.start()

    def on_thread_finished(self):
        print("Thread finished")
        self.thread.deleteLater()


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    app.exec_()

非常“不雅”,但它傳達了這個想法。

一個更簡單的替代方案是簡單地使用QThread::currentThread() ,在這種情況下,您的Worker::run方法變為......

class Worker(QObject):
    def run(self):
        time.sleep(1)
        print("Worker is finished")

        # We're done so ask the `QThread` to terminate.
        QThread.currentThread().quit()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM