为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

aluckdog 2021-08-17 10:44:28
我正在编写的一些分析代码之上构建一个界面,该代码执行一些 SQL 并处理查询结果。在我想向用户公开的这个分析代码中,有许多事件的日志记录。因为分析代码运行时间相当长,而且我不希望 UI 被阻塞,所以到目前为止我是通过将分析函数放入自己的线程来完成的。我现在拥有的简化示例(完整脚本):import sysimport timeimport loggingfrom PySide2 import QtCore, QtWidgetsdef 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 问题以及如何处理从多个进程写入单个日志文件的食谱示例,但我无法围绕如何使这些想法适应我的想法我想在这里做。
查看完整描述

2 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

信号不会在进程之间传输数据,因此对于这种情况,必须使用管道然后发出信号:


# other imports

import 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


# ...


查看完整回答
反对 回复 2021-08-17
  • 2 回答
  • 0 关注
  • 389 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号