使用 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 信号永远不会被调用。