【问题标题】:PyQt5: Thread Not Ending? Process finished with exit code -1PyQt5:线程没有结束?进程以退出代码 -1 结束
【发布时间】:2021-06-21 23:42:39
【问题描述】:

下面的代码运行良好并完成了它的工作。但是,当我退出 GUI 时,python 文件没有完成处理。

当我运行 pycharm debug run 然后强制终止调试时,我收到消息 "进程以退出代码 -1 结束"。

谁能帮我找出导致此错误的原因?

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget
from pybithumb import WebSocketManager
from PyQt5.QtCore import QThread, pyqtSignal

class OverViewWorker(QThread):
    data24Sent = pyqtSignal(int, float, int, float, int, int)
    dataMidSent = pyqtSignal(int, float, float)

    def __init__(self, ticker):
        super().__init__()
        self.ticker = ticker
        self.alive = True

    def run(self):
        wm = WebSocketManager("ticker", [f"{self.ticker}_KRW"], ["24H", "MID"])
        while self.alive:
            data = wm.get()
            if data['content']['tickType'] == "MID":
                self.dataMidSent.emit(int(data['content']['closePrice']),
                    ## Deleted
            else:
                self.data24Sent.emit(int(data['content']['closePrice']),
                    ## Deleted

    def close(self):
        self.alive = False

class OverviewWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        uic.loadUi("resource/overview.ui", self)

        self.ticker = ticker
        self.ovw = OverViewWorker(ticker)
        self.ovw.data24Sent.connect(self.fill24Data)
        self.ovw.dataMidSent.connect(self.fillMidData)
        self.ovw.start()

    def fill24Data(self, currPrice, volume, highPrice, value, lowPrice, PrevClosePrice):
        ## Deleted

    def fillMidData(self, currPrice, chgRate, volumePower):
        ## Deleted

    def closeEvent(self, event):
        self.ovw.close()

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    ob = OverviewWidget()
    ob.show()
    exit(app.exec_())

【问题讨论】:

  • 您预计强制终止后会发生什么?
  • 我试图理解为什么它没有在终端上显示“进程以退出代码 0 完成”,或者上述代码是否意味着不被终止。

标签: python pyqt5 qthread


【解决方案1】:

在您的代码中,QThread.run() 方法进入了一个 while True 循环,它永远不会允许任何 CPU 时间来执行 close 方法并将 self.alive 更改为 False,因此即使您发出 close,该循环也永远不会结束来自 QWidget 的信号。

然后你试图退出一个仍在运行的线程,这会给你-1返回码,因为你的 QThread 在没有完成它的任务的情况下被强行杀死。

如果您添加了从循环中更新活动参数的可能性,您可以摆脱这个问题,但它需要 QThread 访问 QWidget 的参数,这可能不是您想要的。

此外,使用 QThread.wait() 方法可以帮助您进行同步,因为它会强制延迟 QWidget 的退出,直到 ovw 从运行返回。 由于您的 -1 返回代码可能只是由于您的 QApplication 在线程完成之前退出,因此同步退出将缓解这种情况。

这是基于您的代码的示例:

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget
from pybithumb import WebSocketManager
from PyQt5.QtCore import QThread, pyqtSignal

class OverViewWorker(QThread):
    data24Sent = pyqtSignal(int, float, int, float, int, int)
    dataMidSent = pyqtSignal(int, float, float)

    def __init__(self, ticker, master):
        super().__init__()
        self.ticker = ticker
        self.master = master
        self.alive = True

    def run(self):
        wm = WebSocketManager("ticker", [f"{self.ticker}_KRW"], ["24H", "MID"])
        while self.alive:
            data = wm.get()
            if data['content']['tickType'] == "MID":
                self.dataMidSent.emit(int(data['content']['closePrice']),
                    ## Deleted
            else:
                self.data24Sent.emit(int(data['content']['closePrice']),
                    ## Deleted

            self.get_alive_from_master()

        # Do here anything you want in the thread before quitting.

    def get_alive_from_master(self):
        self.alive = master.ovw_alive

class OverviewWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        uic.loadUi("resource/overview.ui", self)

        self.ticker = ticker
        self.ovw = OverViewWorker(ticker, self)
        self.ovw.data24Sent.connect(self.fill24Data)
        self.ovw.dataMidSent.connect(self.fillMidData)
        self.ovw_alive = True
        self.ovw.start()

    def fill24Data(self, currPrice, volume, highPrice, value, lowPrice, PrevClosePrice):
        ## Deleted

    def fillMidData(self, currPrice, chgRate, volumePower):
        ## Deleted

    def closeEvent(self, event):
        self.ovw_alive = False
        self.ovw.wait()

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    ob = OverviewWidget()
    ob.show()
    exit(app.exec_())

【讨论】:

    【解决方案2】:

    如果最后一个窗口关闭,Qt 应用程序将退出,如果还有正在运行的线程,它会终止它们。它可以用app.setQuitOnLastWindowClosed(False) 覆盖。在这种情况下,您必须在线程 finished 上调用 app.quit() 来终止应用程序。

    【讨论】:

    • 感谢您的回答。我在app = QApplication(sys.argv) 下方添加了app.setQuitOnLastWindowClosed(False)。但是,我得到了相同的结果。你能告诉我如何应用你的答案吗?
    猜你喜欢
    • 2016-03-25
    • 2018-03-07
    • 2014-01-04
    • 2017-11-03
    • 2017-01-19
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    相关资源
    最近更新 更多