3

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

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

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

4

2 回答 2

4

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

Fork 维基百科页面

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

这不是 Python 独有的。这发生在任何被派生的 UNIX 进程上,无论它是用 C、Perl 还是 Python 实现的。

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

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

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

于 2013-02-01T10:00:15.900 回答
3

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

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

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

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

于 2013-02-01T10:13:25.117 回答