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

多进程导致文件日志异常,为何一个Handler会干扰另一个?

问题描述

多进程会导致文件日志出现异常:

  • 已写入的日志行可能被删除
  • 新日志行可能无法写入
  • 日志行顺序可能错乱

不使用多进程时,日志功能正常。

我了解可以使用QueueHandler解决,但想明白为何向某个Handler写入日志时,会干扰另一个Handler的正常工作。

复现代码

设置USE_MP=False或取消exit()的注释,可验证不执行多进程代码时日志功能正常。

import logging
import multiprocessing
import time
from multiprocessing import Pool
from typing import Dict, List

USE_MP = True

logger = logging.getLogger()
logger.addHandler(logging.FileHandler(filename="test.log", mode="w"))
logger.setLevel(logging.DEBUG)

mplogger = multiprocessing.log_to_stderr()
mplogger.addHandler(logging.StreamHandler())
mplogger.setLevel(logging.DEBUG)


def time_consuming_function(file_name):
    logger.info(f"Running time_consuming_function with {file_name}")
    time.sleep(1)
    return file_name, file_name


def mp(file_names: List[str]) -> Dict[str, str]:
    logger.info(f"Running mp...")
    with Pool() as p:
        return {
            file_name: file_name
            for file_name, file_name in p.imap_unordered(
                time_consuming_function, file_names
            )
        }


def non_mp(file_names: List[str]) -> Dict[str, str]:
    logger.info(f"Running non-mp...")
    return {
        file_name: file_name
        for file_name, file_name in map(time_consuming_function, file_names)
    }


def main():
    logger.info("Start run...")
    file_names = list("ABCDE")
    # exit()
    if USE_MP:
        mp(file_names)
    else:
        non_mp(file_names)
    logger.info("End run.")


if __name__ == "__main__":
    main()

Python版本:3.7

问题解答

这得从Python多进程的底层机制说起:

  • 当你用Pool创建子进程时,系统会通过fork(Unix)或spawn(Windows)生成新进程。子进程会继承父进程的文件描述符,但每个进程的文件指针位置是独立维护的。
  • 你的代码里,父进程启动时就用FileHandler打开了test.log(mode="w"),此时文件被清空,文件指针停在开头。子进程创建后,各自拿着这个文件的描述符,但它们的指针初始位置都是开头——父进程写入日志后指针已经移到后面,子进程写入时就会从开头覆盖父进程的内容,这就是日志行被“删除”的原因。
  • 多个子进程同时写入时,没有任何同步机制,各自的写入操作会互相穿插,导致日志顺序错乱;甚至会因为文件指针的冲突,出现部分内容写不进去的情况。

你觉得是“一个Handler干扰另一个”,其实本质是同一个文件被多个进程的Handler同时操作,每个Handler都独立管理自己的文件状态,完全没有协调,自然会出各种问题。

QueueHandler之所以能解决,是因为它把所有进程的日志事件都扔进一个队列,交给单独的一个线程/进程统一写入文件,保证了文件操作的原子性和顺序性,从根源上避免了多进程直接操作文件的冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:46:40