如果子进程结束则终止应用程序
Terminate application if subprocess ends
我有一个应用程序正在其主线程中进行一些数据处理。到目前为止,它是一个纯控制台应用程序。现在我不得不添加一个用于可视化目的的 QT 应用程序,并将其作为一个单独的线程来完成。
如果QTWindow关闭了,主线程当然还有运行s。 window 关闭后如何终止主线程?
class Window(threading.Thread)
def __init__(self, data_getter):
super(Window, self).__init__()
self.getter = data_getter
def update(self):
data = self.getter()
#update all UI widgets
def run(self):
app: QApplication = QApplication([])
app.setStyleSheet(style.load_stylesheet())
window = QWidget()
window.setWindowTitle("Test Widget")
window.setGeometry(100, 100, 600, 300)
layout = QGridLayout()
self.LABEL_state: QLabel = QLabel("SM State: N/A")
layout.addWidget(self.LABEL_state)
window.setLayout(layout)
window.show()
timer = QTimer()
timer.timeout.connect(self.update)
timer.start(1000)
app.exec_()
class Runner:
def __init__(self)
pass
def data_container(self):
return data
def process_data(self):
#do the data processing
def main():
runner: Runner = Runner()
time.sleep(1)
w = Window(runner.data_container)
w.start()
while True:
runner.process_data()
time.sleep(2)
if __name__ == "__main__": main()
我最好的想法是给 Window Runner 的另一个函数引用,然后在 Window 中注册到 atexit
并设置一个经常在内部检查的终止标志主进程(Runner)。有更好的方法吗?我知道将 QApp 运行 作为主要进程可能会更好,但在这种情况下我不想这样做。
这里基本上有两个问题:跨两个线程同步事件,以及从外部停止 运行ning 线程。你解决后一个问题的方式可能会影响你解决前一个问题的方法。非常广泛地,您可以:
- 在主循环中轮询一些标志(在您的情况下,
main
中的 while True
循环将是一个明显的目标,可能会将逻辑移至 process_data
并使其 运行完成),或
- 使用某种机制停止包含进程(如信号),可选择注册清理代码以使事情进入已知状态。
无论哪种情况,您都可以随心所欲地设计 api,但是 .stop()
或 .cancel()
方法是非常正常的解决方案。
依赖轮询的问题在于,最坏情况下的响应时间是主循环的整个周期。如果这不可接受,您可能想要触发包含进程或寻找更频繁地检查的方法(如果您的 process_data()
需要 << 2s
到 运行,请将 sleep(2)
替换为循环更小的延迟并在那里轮询标志)。
如果通过设置标志停止不可行,您可以触发包含进程。这通常意味着触发代码是 运行ning 在不同的 thread/process 中。 Python 的线程没有 .terminate()
,但 multiprocessing.Process
是 do,因此您可以将处理委托给一个进程,然后让主代码调用 .terminate()
(或者自己获取pid,手动发送信号)。在这种情况下,主代码在发出信号之前什么都不做,或者可能什么都不做。
最后,图形线程和处理线程之间的通信取决于您如何实现其余部分。对于简单地设置一个标志,暴露一个方法就可以了。如果将处理代码移动到 Process
并且主线程空闲,请使用阻塞事件来避免 busy-looping.
是的,如果图形线程是主线程并自行启动和停止处理代码,那会更容易。除非您知道这会使事情变得非常复杂,否则请查看它以了解您需要进行多少更改才能做到这一点:设计良好的数据处理代码应该只是获取数据、处理数据并将其推出。如果将它放入一个线程中是一项艰巨的工作,那么该设计可能需要重新审视。最后还有 'nuclear option' 只是在 window 循环中获取主线程的 pid 并终止它。这太骇人听闻了,但对于演示工作来说可能已经足够好了。
我有一个应用程序正在其主线程中进行一些数据处理。到目前为止,它是一个纯控制台应用程序。现在我不得不添加一个用于可视化目的的 QT 应用程序,并将其作为一个单独的线程来完成。
如果QTWindow关闭了,主线程当然还有运行s。 window 关闭后如何终止主线程?
class Window(threading.Thread)
def __init__(self, data_getter):
super(Window, self).__init__()
self.getter = data_getter
def update(self):
data = self.getter()
#update all UI widgets
def run(self):
app: QApplication = QApplication([])
app.setStyleSheet(style.load_stylesheet())
window = QWidget()
window.setWindowTitle("Test Widget")
window.setGeometry(100, 100, 600, 300)
layout = QGridLayout()
self.LABEL_state: QLabel = QLabel("SM State: N/A")
layout.addWidget(self.LABEL_state)
window.setLayout(layout)
window.show()
timer = QTimer()
timer.timeout.connect(self.update)
timer.start(1000)
app.exec_()
class Runner:
def __init__(self)
pass
def data_container(self):
return data
def process_data(self):
#do the data processing
def main():
runner: Runner = Runner()
time.sleep(1)
w = Window(runner.data_container)
w.start()
while True:
runner.process_data()
time.sleep(2)
if __name__ == "__main__": main()
我最好的想法是给 Window Runner 的另一个函数引用,然后在 Window 中注册到 atexit
并设置一个经常在内部检查的终止标志主进程(Runner)。有更好的方法吗?我知道将 QApp 运行 作为主要进程可能会更好,但在这种情况下我不想这样做。
这里基本上有两个问题:跨两个线程同步事件,以及从外部停止 运行ning 线程。你解决后一个问题的方式可能会影响你解决前一个问题的方法。非常广泛地,您可以:
- 在主循环中轮询一些标志(在您的情况下,
main
中的while True
循环将是一个明显的目标,可能会将逻辑移至process_data
并使其 运行完成),或 - 使用某种机制停止包含进程(如信号),可选择注册清理代码以使事情进入已知状态。
无论哪种情况,您都可以随心所欲地设计 api,但是 .stop()
或 .cancel()
方法是非常正常的解决方案。
依赖轮询的问题在于,最坏情况下的响应时间是主循环的整个周期。如果这不可接受,您可能想要触发包含进程或寻找更频繁地检查的方法(如果您的 process_data()
需要 << 2s
到 运行,请将 sleep(2)
替换为循环更小的延迟并在那里轮询标志)。
如果通过设置标志停止不可行,您可以触发包含进程。这通常意味着触发代码是 运行ning 在不同的 thread/process 中。 Python 的线程没有 .terminate()
,但 multiprocessing.Process
是 do,因此您可以将处理委托给一个进程,然后让主代码调用 .terminate()
(或者自己获取pid,手动发送信号)。在这种情况下,主代码在发出信号之前什么都不做,或者可能什么都不做。
最后,图形线程和处理线程之间的通信取决于您如何实现其余部分。对于简单地设置一个标志,暴露一个方法就可以了。如果将处理代码移动到 Process
并且主线程空闲,请使用阻塞事件来避免 busy-looping.
是的,如果图形线程是主线程并自行启动和停止处理代码,那会更容易。除非您知道这会使事情变得非常复杂,否则请查看它以了解您需要进行多少更改才能做到这一点:设计良好的数据处理代码应该只是获取数据、处理数据并将其推出。如果将它放入一个线程中是一项艰巨的工作,那么该设计可能需要重新审视。最后还有 'nuclear option' 只是在 window 循环中获取主线程的 pid 并终止它。这太骇人听闻了,但对于演示工作来说可能已经足够好了。