【问题标题】:Is a logger accessible to both parent and child processes?记录器是否可供父进程和子进程访问?
【发布时间】:2013-02-01 09:51:41
【问题描述】:

在python中,如果父进程中配置了记录器,那么子进程是否也会获取该记录器?更清楚地说,在我的应用程序中,我通过执行logger = logging.getlogger() 并向其添加处理程序来为父进程配置根记录器。现在,当一个子进程被分叉时,它会这样做

logger = logging.getlogger()
logger.info("dfsdf")

然后根据父级的根记录器处理所有日志。我没有为孩子配置根记录器。这怎么可能?它们是两个不同的进程,那么它们如何拥有相同的记录器?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    当您派生一个进程时,它会“继承”父进程内存,包括记录器配置。

    来自Fork Wikipedia page

    fork 操作为孩子创建了一个单独的地址空间。子进程拥有父进程所有内存段的精确副本,但如果实现了写时复制语义,则可能不会分配实际的物理内存(即,两个进程可能暂时共享相同的物理内存段) .父进程和子进程拥有相同的代码段,但彼此独立执行。

    这不是 Python 独有的;任何派生的 UNIX 进程都会发生这种情况,无论它是用 C、Perl 还是 Python 实现的。

    multiprocessing module 使用它(在支持它的平台上)快速启动新进程。

    请注意,继承记录器可能会导致竞争条件; logging 模块只知道线程安全;它使用线程锁来序列化对处理程序的访问,但该锁不是跨进程共享的(子进程中的所有内容都是副本,而不是同一个对象)。

    这意味着当您同时记录来自父级和子级的消息时,当操作系统在将日志条目写入文件时在两个进程之间切换时,日志条目最终可能会混合在一起。

    【讨论】:

    • 感谢您消除我的疑问。如果我愿意,这是否使我能够直接在子进程中使用父记录器,而不是在分叉时将其作为参数从父进程传递给子进程?这是一个正确的方法吗?
    • 您可以使用 fork() 的结果来执行分叉后的操作来清理这样的情况(重定向日志),或者使用带有类似 log4j 的 API 的日志记录过程。
    • 您好,您能否提出一个在分叉后进行清理操作的好方法。这在我的代码中造成了很多问题。
    • 在分叉之后而不是之前设置日志记录?
    • @alice:如果您在分叉后需要清理,而不仅仅是因为记录竞争条件,您可能根本不需要分叉。如果您只是在另一个进程中运行某些任务,并且不需要该进程拥有初始进程对象的完整副本,请使用子进程库。
    【解决方案2】:

    有两件事可能会让您感到困惑。

    1. “同一个记录器对象。”对象当然不一样,就像子进程中的所有对象都与父进程中的对象不一样。子进程是其父进程的完整副本,具有单独的地址空间。这意味着它们不共享任何内存。如果一个对象位于父进程中的某个内存地址,则在 fork 后子进程将有一个相同的对象位于同一地址。但是地址在不同的地址空间,内存不共享,分叉完成后对象之间没有关联。因此,对您的问题的简短回答是:对象不一样。

    2. 记录器对象可能在分叉完成之前打开了一个文件。打开的文件由子进程继承。这意味着这两个进程对单个文件有两个文件句柄。这是一个同步问题。

    UPD:我查看了 Python 2.7 安装中的日志记录模块源代码。它使用threading.RLock 来同步日志访问。这意味着您不能在父进程和子进程中安全地使用相同的日志文件。您必须关心具有不同日志的子进程和父进程。它是一个守护程序吗?如果是,通常父进程不需要太多日志记录,可以使用单独的记录器。

    【讨论】:

    • threading.RLock 支持多进程吗?我觉得不应该。
    • @m.brindley:没有。锁与其他所有内容一起复制到子进程。父子进程锁不通信。
    • 它只用于同步线程,根本不知道其他进程。因此日志可能已损坏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多