【问题标题】:Cancel background task (terminate QThread) in PyQt在 PyQt 中取消后台任务(终止 QThread)
【发布时间】:2022-03-20 19:33:43
【问题描述】:

这个问题和this one有很大关系,没有解决办法,但又不完全一样。

我想问一下有没有办法在 PyQt 中启动后台任务,并且可以通过按下按钮来kill它。

我的问题是我有一个用户界面和一些需要一段时间来计算的外部(第 3 方)函数。为了在任务计算时不冻结用户界面,我使用QThread 在后台运行它们,并在它们完成时使用signals 同步用户界面。

但是,我想添加外部用户按下按钮并取消当前任务的选项(因为不再需要/不需要该任务)。

在我看来,就像 linux 中的 kill -9 *task* 一样简单,但在 Qt 中很难获得/混淆。

现在我正在使用以下形式的自定义 Qthread:

mythread = Mythread()
mythread.finished.connect(mycallback)
mythread.start()

其中Mythread 继承QThread 覆盖run 方法。

在用户界面中,有一个按钮试图通过以下任一方式终止该线程:

mythread.exit(0)
mythread.quit()
mythread.terminate()

它们都不起作用...我知道文档指出terminate 方法确实有奇怪的行为...

所以问题是..我面对这个问题错了吗?如何杀死一个QThread?如果不可能,有什么替代方法吗?

谢谢!

【问题讨论】:

  • 你是在UI类的成员变量中还是在局部变量中保留对线程的引用?
  • @qurban 是的,我愿意。那不是问题。问题是目前QThread没有查杀机制。
  • 请发布最小的工作代码,以便我可以调试它。我总是使用terminate 方法杀死QThread,它总是有效。我不知道为什么这对你的情况不起作用。

标签: python multithreading pyqt kill qthread


【解决方案1】:

以您建议的方式尝试杀死 QThread 是一个非常常见的错误。这似乎是由于未能意识到需要停止的是长时间运行的任务,而不是线程本身。

任务被移到工作线程,因为它阻塞了主/GUI 线程。但是一旦任务被移动,这种情况并没有真正改变。它将以与阻塞主线程完全相同的方式阻塞 工作线程。要使线程完成,任务本身要么必须正常完成,要么以某种方式以编程方式停止。也就是说,必须做一些事情来让线程的run() 方法正常退出(这通常需要打破阻塞循环)。

取消长时间运行的任务的常用方法是通过简单的停止标志:

class Thread(QThread):
    def stop(self):
        self._flag = False

    def run(self):
        self._flag = True
        for item in get_items():
            process_item(item)
            if not self._flag:
                break
        self._flag = False

【讨论】:

  • 我面临的问题是我的run 方法调用了第三方库,比如scikits-learn 试图学习分类器,这可能需要几分钟到几小时。所以我的跑步可能看起来像self.classifier.train(self.X)。在这种情况下,将它作为线程/子进程运行并能够杀死它的最佳选择是什么?
  • @imaluengo。如果你无法控制长时间运行的任务,那么你应该使用multiprocessing,而不是线程。
  • 谢谢!我会试一试,然后回来。
猜你喜欢
  • 2015-09-08
  • 2021-10-25
  • 2022-01-06
  • 2011-01-25
  • 2020-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多