Qt Quick(Python)开发过程中多线程的使用

前言

在使用 PySide2 和 Qt Quick 开发应用程序时,如果在程序启动时创建了一个新的线程,并且在关闭主窗口时程序没有退出,这可能是由于后台线程仍在运行,而主线程(GUI 线程)已经退出。

为了确保程序正确退出,需要确保所有后台线程在主窗口关闭时也被妥善处理。

以下是一些可能的解决方案:

设置线程为守护线程

在 Python 中,可以将线程设置为守护线程,这样当主线程退出时,守护线程会自动退出。

1
2
3
4
5
6
7
8
9
10
11
import threading

def background_task():
# 你的后台任务代码
while True:
pass

# 创建并启动后台线程
background_thread = threading.Thread(target=background_task)
background_thread.daemon = True # 设置为守护线程
background_thread.start()

在主窗口关闭时停止后台线程

如果后台线程需要执行一些清理操作,可以显式地停止后台线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import threading
import time

class BackgroundWorker(threading.Thread):
def __init__(self):
super().__init__()
self.stop_event = threading.Event()

def run(self):
while not self.stop_event.is_set():
# 你的后台任务代码
time.sleep(1)

def stop(self):
self.stop_event.set()

# 创建并启动后台线程
background_worker = BackgroundWorker()
background_worker.start()

# 在主窗口关闭时停止后台线程
def on_close():
background_worker.stop()
background_worker.join() # 等待线程退出

# Qt Quick 的窗口关闭事件处理
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine

app = QApplication([])
engine = QQmlApplicationEngine()
engine.quit.connect(on_close) # 连接到窗口关闭事件

使用 QThread

在 Qt 应用程序中,推荐使用 QThread 而不是 Python 的 threading.Thread,因为 QThread 与 Qt 的事件循环更紧密地集成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from PySide2.QtCore import QThread, Signal, Slot
# Qt Quick 的窗口关闭事件处理
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine

class BackgroundWorker(QThread):
def run(self):
while not self.isInterruptionRequested():
# 你的后台任务代码
self.msleep(1000)

# 创建并启动后台线程
background_worker = BackgroundWorker()
background_worker.start()

# 在主窗口关闭时请求线程中断
def on_close():
background_worker.requestInterruption()
background_worker.waitForFinished()

app = QApplication([])
engine = QQmlApplicationEngine()
engine.quit.connect(on_close) # 连接到窗口关闭事件

使用 QObject 的析构函数

确保在主窗口关闭时,所有相关的 QObject 对象被正确销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from PySide2.QtCore import QObject, Signal, Slot
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine

class BackgroundWorker(QObject):
def __init__(self):
super().__init__()
self.thread = QThread()
self.moveToThread(self.thread)
self.thread.started.connect(self.run)
self.thread.start()

@Slot()
def run(self):
while True:
# 你的后台任务代码
time.sleep(1)

def cleanup(self):
self.thread.quit()
self.thread.wait()

# 创建后台工人类
background_worker = BackgroundWorker()

# 在主窗口关闭时进行清理
def on_close():
background_worker.cleanup()

app = QApplication([])
engine = QQmlApplicationEngine()
engine.quit.connect(on_close) # 连接到窗口关闭事件

通过以上方法,可以确保在关闭主窗口时,后台线程被正确停止,从而使整个应用程序能够顺利退出。

获取所在线程

1
2
3
4
import threading     

current_thread = threading.current_thread()
print(f"Worker thread: {current_thread.name} (ID: {current_thread.ident})")