python multiprocessing - 将子进程日志发送到在父进程中运行的 GUI

我正在编写的一些分析代码之上构建一个界面,该代码执行一些 SQL 并处理查询结果。在我想向用户公开的这个分析代码中,有许多事件的日志记录。因为分析代码运行时间相当长,而且我不希望 UI 被阻塞,所以到目前为止我是通过将分析函数放入自己的线程来完成的。


我现在拥有的简化示例(完整脚本):


import sys

import time

import logging

from PySide2 import QtCore, QtWidgets


def long_task():

    logging.info('Starting long task')

    time.sleep(3) # this would be replaced with a real task

    logging.info('Long task complete')


class LogEmitter(QtCore.QObject):

    sigLog = QtCore.Signal(str)


class LogHandler(logging.Handler):

    def __init__(self):

        super().__init__()

        self.emitter = LogEmitter()

    def emit(self, record):

        msg = self.format(record)

        self.emitter.sigLog.emit(msg)


class LogDialog(QtWidgets.QDialog):

    def __init__(self, parent=None):

        super().__init__(parent)

        log_txt = QtWidgets.QPlainTextEdit(self)

        log_txt.setReadOnly(True)

        layout = QtWidgets.QHBoxLayout(self)

        layout.addWidget(log_txt)

        self.setWindowTitle('Event Log')

        handler = LogHandler()

        handler.emitter.sigLog.connect(log_txt.appendPlainText)

        logger = logging.getLogger()

        logger.addHandler(handler)

        logger.setLevel(logging.INFO)


class Worker(QtCore.QThread):

    results = QtCore.Signal(object)


    def __init__(self, func, *args, **kwargs):

        super().__init__()

        self.func = func

        self.args = args

        self.kwargs = kwargs


    def run(self):

        results = self.func(*self.args, **self.kwargs)

        self.results.emit(results)


class MainWindow(QtWidgets.QMainWindow):



这工作正常,除了我需要能够允许用户停止执行分析代码。我读过的一切都表明没有办法很好地中断线程,所以使用multiprocessing库似乎是要走的路(没有办法重新编写分析代码以允许定期轮询,因为大部分时间是只花等待查询返回结果)。通过使用multiprocessing.Pool和以不阻塞 UI 的方式执行分析代码,很容易获得相同的功能apply_async。



但我似乎无法弄清楚如何从子进程检索日志输出并将其传递给父进程以更新日志对话框。我已经阅读了几乎所有关于此的 SO 问题以及如何处理从多个进程写入单个日志文件的食谱示例,但我无法围绕如何使这些想法适应我的想法我想在这里做。


aluckdog
浏览 390回答 2
2回答

繁星淼淼

信号不会在进程之间传输数据,因此对于这种情况,必须使用管道然后发出信号:# other importsimport threading# ...class LogHandler(logging.Handler):    def __init__(self):        super().__init__()        self.r, self.w = multiprocessing.Pipe()        self.emitter = LogEmitter()        threading.Thread(target=self.listen, daemon=True).start()    def emit(self, record):        msg = self.format(record)        self.w.send(msg)    def listen(self):        while True:            try:                msg = self.r.recv()                self.emitter.sigLog.emit(msg)            except EOFError:                break# ...
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python