目录
多线程&多任务介绍
多线程&多任务通常是指将一个任务或多个任务运行在子线程,并且子线程可以独立启动,或通过线程池启动。子线程通常用于执行以下类型的任务:
- 长时间运行的任务:子线程适合处理那些耗时较长的任务,以避免阻塞主线程的执行。例如,进行复杂的计算、图像处理、视频编解码等任务可以放在子线程中执行,以保持应用程序的响应性。
- 阻塞型任务:如果有一些阻塞型的操作,可能会导致主线程被阻塞,例如进行网络请求、文件读写、数据库查询等。将这些任务放在子线程中执行可以确保主线程的流畅运行,同时避免应用程序的无响应状态。
- 并行处理任务:如果有多个独立的任务需要同时执行,可以将它们分配给多个子线程来实现并行处理。例如,批量下载多个文件、同时进行多个数据处理任务等。
- 异步操作:子线程可以用于执行异步操作,例如在后台处理数据、定时任务、监听外部设备的输入等。这样可以保持应用程序的其他部分正常运行,同时处理异步任务。
需要注意的是,使用子线程需要谨慎处理线程间的数据共享和同步问题,以避免出现竞态条件或其他并发问题。在 PyQt 中,可以使用线程间通信机制(如信号槽机制)来安全地传递数据和操作UI元素。
多线程管理
通常线程有两种启动方式,分别对应不同的使用场景:
- 将任务直接运行在一个独立的线程里
用于执行一次性长期任务(例如:并行任务,多线程下载),长期循环阻塞式接收任务(例如:接收蓝牙、网络、串口消息)
- 将任务运行在一个线程池的线程里
用于执行频繁触发型短期任务,避免线程资源浪费(例如:数据库操作、文件写入、网络数据下载),因为线程池可以重复利用其内部维护的N个线程,按需创建,减少资源的申请与释放操作。
1. 拷贝依赖
"""
线程管理器,用于管理线程的创建、启动、停止等。
包含两种线程启动方式:
1. start 运行一个独立线程,用于执行一次性短期任务(例如:并行任务,多线程下载)、长期循环接收任务(例如:阻塞式接收蓝牙、串口消息)
2. start_in_thread_pool 在一个线程池里运行任务,用于执行非定期触发型短期任务,避免线程资源浪费(例如:数据库操作、文件写入、网络数据下载)
其中包含了一个 Worker 类
● Worker 类用于创建线程任务
Worker 类继承自 QRunnable 类,用于创建线程任务。
● 其中包含了一个 run 方法,用于执行线程任务
● 一个 signal_connect 方法,用于连接信号槽
● 一个 stop 方法,用于停止线程任务
● 一个 emit_msg 方法,用于发送消息。
"""
import inspect
from typing import Callable
from PyQt5.QtCore import pyqtSignal, QObject, QRunnable, QThread, QThreadPool
class WorkerSignals(QObject):
signal_finished = pyqtSignal()
signal_error = pyqtSignal(Exception)
signal_result = pyqtSignal(object)
signal_msg = pyqtSignal(object)
class Worker(QRunnable):
def __init__(self, target: Callable, args=None, kwargs=None):
super().__init__()
self.setAutoDelete(True) # 自动删除,避免内存泄漏
self.__func = target
self.__args = args if args else ()
self.__kwargs = kwargs if kwargs else {}
self.__signals = WorkerSignals()
self.is_running = False
self.worker_thread: WorkerThread = None
def run(self):
self.is_running = True
try:
# 如果func的第一个参数是Worker类型,则将self作为第一个参数传入
if self.__is_worker_func