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

问题描述 投票:0回答:2

这个问题与这个有很大关系,后者没有解决方案,但并不完全相同。

我想问是否有一种方法可以在PyQt中启动后台任务,并且能够通过按按钮来

kill
它。

我的问题是我有一个用户界面和一些外部(第三方)函数,需要一段时间才能计算。为了在任务计算时不冻结用户界面,我使用

QThread
在后台运行它们,并在它们完成时使用
signals
同步 UI。

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

对我来说,在 Linux 中看起来像

kill -9 *task*
一样简单的东西,在 Qt 中很难/很困难地获得。

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

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

其中

Mythread
继承 QThread 重写
run
方法。

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

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

它们都不起作用...我知道文档指出

terminate
方法确实有奇怪的行为...

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

谢谢!

python multithreading pyqt kill qthread
2个回答
4
投票

尝试按照您建议的方式杀死

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

0
投票

我也面临着与

QThreads
同样的挑战。经过多次实验,我发现以下解决方案对于在 PyQt5 中管理线程非常有效:

解决方案

关键是使用

requestInterruption
方法,该方法允许线程检查中断请求并以受控方式终止自身。代码如下:

from PyQt5.QtCore import QThread, pyqtSignal


class Worker(QThread):
    def run(self):
        while True:
            if self.isInterruptionRequested():
                break
            # do time consuming job here
            QThread.sleep(100)  # to illustrate expensive task
class MainWindow:
    # init and other mechanism 

    def kill_worker():
        # Gently kills the thread
        if self._thread.isRunning():
            self._thread.requestInterruption() # kills straightforwardly
            self._thread.quit()
            self._thread.wait()
        self._thread.deleteLater()

参考

© www.soinside.com 2019 - 2024. All rights reserved.