You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行的多进程间共享已配置的Logger?

多进程日志异常排查方向(仅输出3条日志、日志文件无内容)

核心问题定位方向

1. Build类初始化循环逻辑错误

你的builder.py中Build.__init__的循环逻辑完全不符合并行处理预期:每次循环都会启动一个worker进程,随即启动日志线程,等待所有已启动的worker结束后就终止日志线程。这会导致worker进程被逐个串行执行,且日志线程频繁启停,部分日志记录可能因线程生命周期问题丢失。

修正示例:

def __init__(self, q):
    self.queue = q
    self.logger = logging.getLogger('dcre')

    workers = []
    # 先批量启动所有worker进程
    for i in range(5):
        wp = Process(target=self.foo, args=(i,))
        workers.append(wp)
        wp.start()

    # 所有worker启动完成后,启动单个日志线程统一处理
    lp = threading.Thread(target=self.logger_thread)
    lp.start()

    # 等待所有worker执行完毕
    for wp in workers:
        wp.join()

    # 发送终止信号给日志线程
    self.queue.put(None)
    lp.join()

2. Windows spawn模式下的日志实例隔离

Windows多进程默认使用spawn模式,子进程会重新导入模块并初始化全新对象,主进程中配置的logger不会被继承。你当前代码中,子进程执行foo时使用的self.logger是子进程内的全新实例,没有配置QueueHandler,导致日志无法传递到主进程的队列,自然无法被FileHandler写入文件。

修正示例:在子进程内部配置QueueHandler

def foo(self, i):
    # 子进程单独配置QueueHandler,将日志发送到主进程传递的队列
    qh = logging.handlers.QueueHandler(self.queue)
    logger = logging.getLogger('dcre')
    logger.addHandler(qh)
    logger.setLevel('DEBUG')  # 确保级别足够低,不会过滤日志

    msgs = (
        (10, "This is a DEBUG message. You shouldn't see this."),
        (20, 'This is an INFO message. Just so you know.'),
        (30, 'This is a WARNING message. Be careful, yo.'),
        (40, 'This is an ERROR message. Man, you done messed up.'),
        (50, 'This is a CRITICAL message. Game over!')
    )
    logger.log(*msgs[i])

注意:禁止直接传递logger实例给子进程,logging.Logger对象不可被pickle序列化,会触发异常。

3. 日志处理器重复添加与配置冲突

主进程中logger.configure方法多次调用(如按钮重复点击)会重复添加QueueHandler和FileHandler,导致日志重复或处理逻辑混乱;同时logging.basicConfig会给root logger添加StreamHandler,可能干扰自定义logger的级别过滤。

修正示例:添加handler存在性检查

def configure(self, q):
    self.q = q
    # 避免重复添加QueueHandler
    if not any(isinstance(h, logging.handlers.QueueHandler) for h in self.logger.handlers):
        self.qh = logging.handlers.QueueHandler(self.q)
        self.logger.addHandler(self.qh)
    # 避免重复添加FileHandler
    if not any(isinstance(h, logging.FileHandler) for h in self.logger.handlers):
        self.file = logging.FileHandler('log.log')
        self.file.setLevel('DEBUG')
        self.logger.addHandler(self.file)
    # 仅在root logger无handler时调用basicConfig
    if not logging.root.handlers:
        logging.basicConfig(level='INFO')

4. 队列与日志线程的生命周期冲突

GUI中使用全局队列q,每次点击按钮创建Build实例时,都会向同一个队列写入终止信号None。后续启动的日志线程会提前读取到之前的None信号并退出,导致后续worker的日志无法被处理。

建议:每个Build实例使用独立的队列,或者在每次处理前清空队列(注意多线程/进程下的队列操作安全)。

5. 日志级别过滤异常

主进程中logger设置为DEBUG级别,但子进程中的logger默认级别为WARNING,会过滤DEBUG和INFO级别的日志。需要确保子进程中的logger级别也设置为DEBUG,避免日志被过滤。

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:51:11