PyQt中取消后台任务(终止QThread)

Cancel background task (terminate QThread) in PyQt

这个问题和this one有很大关系,虽然没有解,但也不完全一样

我想问一下在 PyQt 中是否有启动后台任务的方法,并且能够通过按下按钮 kill 它。

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

但是,我想为外部用户添加一个选项来按下按钮并取消当前任务(因为任务不再是 needed/desired)。

在我看来,linux 中的 kill -9 *task* 一样简单的东西,在 Qt 中 hard/ofuscated 却很容易获得。

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

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

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

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

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

None 其中有效...我知道文档指出 terminate 方法确实有奇怪的行为...

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

谢谢!

按照您建议的方式尝试杀死 QThread 是一个非常常见的错误。这似乎是由于没有意识到需要停止的是 long-运行 任务,而不是线程本身。

任务已移至工作线程,因为它阻塞了 main/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