PyQT 多进程

2024-01-02 23:48:36

在PyQt中,图形化界面(GUI)是运行在主线程中的,而多进程是在独立的进程中执行的。默认情况下,多进程之间是无法直接共享图形化界面的。

然而,有几种方法可以在多进程中与PyQt的图形化界面进行通信:

  1. 使用进程间通信(Inter-Process Communication,IPC)机制,如管道(Pipe)、共享内存(Shared Memory)或消息队列(Message Queue)。你可以在主线程中创建一个IPC对象,然后将其传递给子进程,子进程可以使用该对象与主线程进行通信。这样,你可以将任务的进度或结果发送回主线程,然后更新图形化界面。

  2. 使用信号与槽机制(Signals and Slots)进行跨线程通信。PyQt提供了线程间通信的机制,你可以在子进程中创建一个线程,然后将该线程与主线程中的槽函数连接起来。子进程可以通过发射信号的方式将任务的进度或结果传递给主线程,然后由主线程的槽函数更新图形化界面。

无论使用哪种方法,都需要小心处理线程或进程间的同步和互斥,以避免出现竞争条件或其他并发问题。

需要注意的是,多进程会引入额外的开销和复杂性,因此在决定使用多进程之前,建议先考虑是否有其他的优化方案,例如使用多线程、异步编程或者优化算法等。

进程间通信

import sys
from PyQt5.QtCore import QProcess, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
import time
# 子进程类
class WorkerProcess(QProcess): # 继承自QProcess,用于表示子进程
    resultReady = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.readyReadStandardOutput.connect(self.handle_output)

    def handle_output(self):
        data = self.readAllStandardOutput().data().decode()
        self.resultReady.emit(data)

# 主窗口类
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('IPC Example')
        self.button = QPushButton('Start', self)
        self.button.clicked.connect(self.start_worker)
        layout = QVBoxLayout()
        layout.addWidget(self.button)
        widget = QWidget(self)
        widget.setLayout(layout)
        self.setCentralWidget(widget)

    def start_worker(self):
        self.button.setEnabled(False)
        self.worker_process = WorkerProcess()
        self.worker_process.finished.connect(self.worker_finished)
        self.worker_process.resultReady.connect(self.handle_result)
        self.worker_process.start('python', ['worker.py'])

    @pyqtSlot(str)
    def handle_result(self, result):
        print(f'Result: {result}')
        # 在这里处理子进程的结果

    def worker_finished(self):
        self.button.setEnabled(True)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

将在终端的的显示结果显示在PyQt上

import sys
from PyQt5.QtCore import QProcess, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QTextEdit

# 子进程类
class WorkerProcess(QProcess):
    resultReady = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.readyReadStandardOutput.connect(self.handle_output)

    def handle_output(self):
        data = self.readAllStandardOutput().data().decode()
        self.resultReady.emit(data)

# 主窗口类
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('IPC Example')
        self.button = QPushButton('Start', self)
        self.button.clicked.connect(self.start_worker)
        self.text_edit = QTextEdit(self)
        layout = QVBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.text_edit)
        widget = QWidget(self)
        widget.setLayout(layout)
        self.setCentralWidget(widget)

    def start_worker(self):
        self.button.setEnabled(False) # 首先禁用按钮
        self.worker_process = WorkerProcess() # 创建一个WorkerProcess对象作为子进程。
        self.worker_process.finished.connect(self.worker_finished) # 子进程的finished信号连接到worker_finished槽函数
        self.worker_process.resultReady.connect(self.handle_result) # 将子进程的resultReady信号连接到handle_result槽函数
        self.worker_process.start('python', ['worker.py']) # 使用start方法启动子进程,执行worker.py脚本

    @pyqtSlot(str)
    def handle_result(self, result): # 槽函数 接收到子进程的输出结果
        self.text_edit.append(result)  # 将结果添加到文本编辑框中

    def worker_finished(self): # 当子进程完成时,将执行worker_finished函数
        self.button.setEnabled(True)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

进程与进程之间通信

在多进程编程中,进程与进程之间可以使用多种方式进行通信,消息队列只是其中一种方式。以下是一些常用的进程间通信(IPC)机制:

  1. 消息队列(Message Queues):进程可以通过消息队列发送和接收消息。消息队列提供了一种异步的通信方式,进程之间可以通过队列传递数据。

  2. 共享内存(Shared Memory):进程可以通过共享内存区域在它们之间共享数据。多个进程可以访问同一块内存,从而实现数据共享。

  3. 管道(Pipes):管道是一种单向的通信方式,用于在两个进程之间传递数据。一个进程充当管道的写入端,另一个进程充当管道的读取端。

  4. 套接字(Sockets):套接字是一种网络编程中常用的通信方式,但它也可以用于进程间通信。进程可以通过套接字在网络上或本地主机上进行通信。

  5. 文件(Files):进程可以通过读写文件的方式进行通信。一个进程可以将数据写入文件,另一个进程可以读取该文件来获取数据。

这些是一些常见的进程间通信方式,每种方式都有其适用的场景和特点。选择适当的通信方式取决于具体的应用需求和设计考虑。

文章来源:https://blog.csdn.net/llf000000/article/details/135349578
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。