pyqt多线程正确写法(PyQt多线程编程实践)

jk 747次浏览

最佳答案PyQt多线程编程实践 多线程编程是当前计算机程序设计中非常重要的一个部分,对于大型的多媒体应用和并行计算等需要同时运行多个任务的应用来说,多线程编程技术可以提高应用的...

PyQt多线程编程实践

多线程编程是当前计算机程序设计中非常重要的一个部分,对于大型的多媒体应用和并行计算等需要同时运行多个任务的应用来说,多线程编程技术可以提高应用的执行效率。PyQt是一个强大的Python GUI框架,其支持多线程编程,本文将通过实践来介绍PyQt多线程编程的正确方法。

1. PyQt多线程编程的需求

在介绍PyQt多线程编程的正确方式前,我们先来看一下什么情况下需要使用多线程编程。在PyQt应用程序中,由于GUI界面是单线程程序,当只有一个线程执行任务时,GUI界面也会被卡住,无法进行操作,这会降低用户体验,甚至让应用程序崩溃。因此,像处理数据高峰期、网络请求等长时间操作时,我们需要使用多线程编程来提高程序的执行效率,同时保证界面的流畅性。

在PyQt中,有两种多线程实现方式,分别是QThread和QThreadPool。

2. 使用QThread编写多线程应用程序

QThread是PyQt自带的线程类,可以直接继承QThread类来实现新的线程。下面我们将通过实例来演示QThread的使用。

首先,我们需要在主线程中实例化一个QThread对象,并将我们自定义的线程类实例化,然后将线程对象的启动信号connect到我们自定义的函数中。这个函数需要被线程来执行,因此我们需要重新实现线程对象的run()函数。具体实现代码如下:

``` import sys from PyQt5.QtCore import QThread from PyQt5.QtWidgets import QApplication, QMainWindow # 自定义线程类 class MyThread(QThread): def __init__(self, parent=None): super(MyThread, self).__init__(parent=parent) def run(self): # 加入要执行的任务 pass class MainWindow(QMainWindow): def __init__(self): super().__init__() self.thread = MyThread() self.thread.start() # 启动线程 self.thread.finished.connect(self.finished) # 设置完成信号连接到槽 def finished(self): print(\"执行完毕\") if __name__ == '__main__': app = QApplication(sys.argv) mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_()) ```

通过上面的代码,我们实现了一个完整的多线程程序。在程序中,我们实例化了一个QThread对象,并将我们自定义的线程类实例化给它,然后启动线程对象并将完成信号连接到槽函数finished()。线程执行的任务需要放到run()函数中。我们通过这种方式实现了多线程编程,可以提高程序执行效率,同时保证了GUI界面的流畅性。

3. 使用QThreadPool编写多线程应用程序

除了QThread,PyQt中还提供了另一种多线程方式QThreadPool。QThreadPool是一个线程池,可以用来管理多个线程的创建和销毁。下面我们将通过实例来演示QThreadPool的使用。

首先,我们需要定义一个自定义的线程类,他会执行我们传入的任务。下面是具体实现:

``` import sys import time from functools import partial from PyQt5.QtCore import QObject, QRunnable, pyqtSignal, pyqtSlot, QThreadPool from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget class WorkerSignals(QObject): \"\"\" 用于给线程池池子发送槽的信号 \"\"\" result = pyqtSignal(dict) class Worker(QRunnable): \"\"\" 任务线程 \"\"\" def __init__(self, fn, *args, **kwargs): super(Worker, self).__init__() self.fn = fn self.args = args self.kwargs = kwargs self.signals = WorkerSignals() @pyqtSlot() def run(self): result = self.fn(*self.args, **self.kwargs) self.signals.result.emit(result) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.threadpool = QThreadPool() print(\"Multithreading with maximum %d threads\" % self.threadpool.maxThreadCount()) layout = QVBoxLayout() self.label = QLabel(\"Display area\") layout.addWidget(self.label) self.button = QPushButton(\"Start\") layout.addWidget(self.button) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) self.button.clicked.connect(self.startTask) def startTask(self): # 声明要执行一个列表任务 todo = [ {'action': 'Sleep', 'seconds': 3}, {'action': 'Wake up', 'seconds': 1}, {'action': 'Read book', 'seconds': 5}, {'action': 'Drink tea', 'seconds': 2}, {'action': 'Eat', 'seconds': 4} ] workerList = [] for i in range(len(todo)): worker = Worker(self.doSomething, **todo[i]) worker.signals.result.connect(self.displayResult) # 接收结果 workerList.append(worker) for worker in workerList: self.threadpool.start(worker) def doSomething(self, **data): \"\"\" 线程任务执行。 \"\"\" print(f'线程{data[\"action\"]}开始执行{data[\"seconds\"]}S的任务。。。') time.sleep(data['seconds']) print(f'线程{data[\"action\"]}已执行完毕。。。') return {'action': data[\"action\"], 'result': 'success'} def displayResult(self, result): print(f'线程{result[\"action\"]}执行结果:{result[\"result\"]}') self.label.setText(f'线程{result[\"action\"]}执行结果:{result[\"result\"]}') if __name__ == '__main__': app = QApplication(sys.argv) mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_()) ```

在上面的代码中,我们定义了两个类——WorkerSignals和Worker。WorkerSignals是一个QObject子类,它负责接收线程执行后的结果,并发射一个信号来传递这个结果;Worker是一个QRunnable子类,它是一个加入到线程池队列中的执行任务。

当我们需要在主线程中启动线程时,只需要实例化一个Worker对象,并将需要执行的任务和参数传递给它。同时,连接worker.signals.result到槽函数self.displayResult,以便接收线程执行的结果。

综上所述,QThreadPool相比QThread,多了一些线程管理的功能。通过线程池池子的功能,我们可以控制线程的数量,从而避免同时运行过多的线程导致应用程序挂起等问题。

总结

在PyQt的多线程编程中,我们有两种实现方式:QThread和QThreadPool。QThread是一个非常基础的多线程类,我们需要通过继承它并重新实现run()函数来实现多线程编程;而QThreadPool是PyQt提供的一个线程池,我们则需要通过继承QRunnable并实现Runnable.run()函数来实现多线程编程。

正确地使用多线程编程技术可以使得PyQt应用程序更加高效和流畅,更好地响应用户的操作。在实际开发中,根据具体的需求来选择合适的线程方式,保证应用程序的高效执行。