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
这个问题和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