使用 QTimer 停止 Qthread
stopping a Qthread with a QTimer
我正在我的 GUI 中启动 Qthread
来执行优化功能。我想包含一个可以中断 Qthread
并立即结束优化函数的停止函数。
我读到不推荐使用 Qthread.terminate()
;无法使用停止标志,因为函数的性质不是循环。
我想过在QThread
中使用一个QTimer
(看门狗定时器)定期检查一个停止标志,如果它被触发,就结束优化功能,但我不能真想像这样的idea怎么写。
有什么想法吗?
class Worker(QObject):
finished = pyqtSignal()
def run(self):
# implement a QTimer here that will somehow interrupt the minimize function
# minimize is an arbitrary function that takes too long to run, and uses child processes to do so
result = minimize(something)
FROM_Optimization_Process,_ = loadUiType(os.path.join(os.path.dirname(__file__),"ui_files/Optimization_process_window.ui"))
class Optimization_process_window(QDialog, FROM_Optimization_Process):
def __init__(self, parent=None):
# first UI
super(Optimization_process_window, self).__init__(parent)
self.setupUi(self)
def start_solving_thread(self):
self.thread = QThread()
self.thread.daemon = True
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.start()
def stop_solving(self):
# implement an interrupt function here
self.thread.quit()
self.thread.wait()
你误解了计时器的工作原理。他们不能以任何方式“中断”线程中的代码 运行。只有当线程中的事件循环空闲并准备好处理定时器事件和信号时,定时器才能工作。如果该线程中的某些代码 运行,则该事件循环将被阻止。
换句话说,你的线程中的 QTimer
将不起作用,除非你时不时地打开事件循环来处理定时器信号。但据我所知,您可能在 minimize(something)
函数中做了一些密集的工作。它完全阻止了事件循环。
如果你想实现worker/thread中断,唯一的办法就是通过周期性的轮询在你的minimize(something)
函数中实现中断。您需要将此函数中的工作拆分为某些块,并在每个块完成后检查 worker/thread 是否应该停止。
QThread
有一个帮助函数。就是QThread.requestInterruption()
和QThread.isInterruptionRequested()
,这些函数是线程安全的。您可以通过调用 QObject.thread()
从您的 worker 访问线程实例。但是,您有责任在完成每个工作块后在代码中足够频繁地检查 QThread.isInterruptionRequested()
。
当然你可以开发你自己的方法来中止工作,可能由互斥锁保护......但是你必须定期检查它。没办法了。
def minimize(self, something): # a method of Worker class
for i in range(1000000):
if i % 1000 == 0: # this is just to represent a block of work
if self.thread().isInterruptionRequested():
return
self.minimize_next_part(something)
self.finished.emit()
那么 stopper 函数应该是:
def stop_solving(self):
self.thread.requestInterruption() # this will unblock the event loop in just a moment
self.thread.quit() # this ends event loop and will emit thread's finished signal
# self.thread.wait() # you do not need this probbaly, it depends...
(对于潜在的语法错误,我很抱歉,我是 C++ 程序员,不是 Pythonista)
我知道这看起来很愚蠢,但实际上没有其他神奇的中断线程机制。您只需要定期轮询。
PS:而不是
self.worker.finished.connect(self.worker.deleteLater)
你应该使用
self.thread.finished.connect(self.worker.deleteLater)
否则,如果线程被中断,worker 将不会被删除,因为 Worker.finished
信号永远不会被调用。
我正在我的 GUI 中启动 Qthread
来执行优化功能。我想包含一个可以中断 Qthread
并立即结束优化函数的停止函数。
我读到不推荐使用 Qthread.terminate()
;无法使用停止标志,因为函数的性质不是循环。
我想过在QThread
中使用一个QTimer
(看门狗定时器)定期检查一个停止标志,如果它被触发,就结束优化功能,但我不能真想像这样的idea怎么写。
有什么想法吗?
class Worker(QObject):
finished = pyqtSignal()
def run(self):
# implement a QTimer here that will somehow interrupt the minimize function
# minimize is an arbitrary function that takes too long to run, and uses child processes to do so
result = minimize(something)
FROM_Optimization_Process,_ = loadUiType(os.path.join(os.path.dirname(__file__),"ui_files/Optimization_process_window.ui"))
class Optimization_process_window(QDialog, FROM_Optimization_Process):
def __init__(self, parent=None):
# first UI
super(Optimization_process_window, self).__init__(parent)
self.setupUi(self)
def start_solving_thread(self):
self.thread = QThread()
self.thread.daemon = True
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.start()
def stop_solving(self):
# implement an interrupt function here
self.thread.quit()
self.thread.wait()
你误解了计时器的工作原理。他们不能以任何方式“中断”线程中的代码 运行。只有当线程中的事件循环空闲并准备好处理定时器事件和信号时,定时器才能工作。如果该线程中的某些代码 运行,则该事件循环将被阻止。
换句话说,你的线程中的 QTimer
将不起作用,除非你时不时地打开事件循环来处理定时器信号。但据我所知,您可能在 minimize(something)
函数中做了一些密集的工作。它完全阻止了事件循环。
如果你想实现worker/thread中断,唯一的办法就是通过周期性的轮询在你的minimize(something)
函数中实现中断。您需要将此函数中的工作拆分为某些块,并在每个块完成后检查 worker/thread 是否应该停止。
QThread
有一个帮助函数。就是QThread.requestInterruption()
和QThread.isInterruptionRequested()
,这些函数是线程安全的。您可以通过调用 QObject.thread()
从您的 worker 访问线程实例。但是,您有责任在完成每个工作块后在代码中足够频繁地检查 QThread.isInterruptionRequested()
。
当然你可以开发你自己的方法来中止工作,可能由互斥锁保护......但是你必须定期检查它。没办法了。
def minimize(self, something): # a method of Worker class
for i in range(1000000):
if i % 1000 == 0: # this is just to represent a block of work
if self.thread().isInterruptionRequested():
return
self.minimize_next_part(something)
self.finished.emit()
那么 stopper 函数应该是:
def stop_solving(self):
self.thread.requestInterruption() # this will unblock the event loop in just a moment
self.thread.quit() # this ends event loop and will emit thread's finished signal
# self.thread.wait() # you do not need this probbaly, it depends...
(对于潜在的语法错误,我很抱歉,我是 C++ 程序员,不是 Pythonista)
我知道这看起来很愚蠢,但实际上没有其他神奇的中断线程机制。您只需要定期轮询。
PS:而不是
self.worker.finished.connect(self.worker.deleteLater)
你应该使用
self.thread.finished.connect(self.worker.deleteLater)
否则,如果线程被中断,worker 将不会被删除,因为 Worker.finished
信号永远不会被调用。