Python从多个进程记录

时间:2011-12-06 17:07:04

标签: python sockets file-io multiprocessing

我有一个可能长时间运行的程序,目前有4个进程,但可以配置为有更多。我使用python的logging研究了logging from multiple processes,并使用了here讨论的SocketHandler方法。我没有任何问题只有一个记录器(没有套接字),但从我读到的,我被告知它最终会出乎意料地失败。据我所知,当你尝试同时写入同一个文件时会发生什么。我的代码基本上执行以下操作:

import logging
log = logging.getLogger(__name__)

def monitor(...):
    # Spawn child processes with os.fork()
    # os.wait() and act accordingly

def main():
    log_server_pid = os.fork()
    if log_server_pid == 0:
        # Create a LogRecordSocketServer (daemon)
        ...
        sys.exit(0)
    # Add SocketHandler to root logger
    ...
    monitor(<configuration stuff>)

if __name__ == "__main__":
    main()

所以我的问题是:我需要在每个log之后创建一个新的os.fork()对象吗?现有的全局log对象会发生什么?

按照我的方式做事,我是否能解决我想避免的问题(多个打开的文件/套接字)?这会失败,为什么会失败(我希望能够判断未来类似的实现是否会失败)?

此外,从多个进程登录到一个文件的“正常”(一个log=表达式)方法以何种方式失败?它是否引发IOError / OSError?或者它只是没有完全将数据写入文件?

如果有人可以提供答案或链接来帮助我,那就太好了。感谢。

FYI : 我正在Mac OS X Lion上进行测试,代码可能最终会在Windows机器上的CentOS 6 VM上运行(如果这很重要)。无论我使用什么解决方案都不需要在Windows上工作,但应该在基于Unix的系统上工作。

更新:这个问题已经开始摆脱日志记录的特定行为,而且更多的是Linux在forks期间使用文件描述符做什么。我拿出了我的一本大学教科书,似乎如果你从两个进程(不是在一个分支之前)中以附加模式打开一个文件,只要你的写入不超过它们,它们都能够正确地写入文件实际的内核缓冲区(虽然可能需要使用行缓冲,但仍然不确定)。这将创建2个文件表条目和一个v节点表条目。打开一个文件然后分叉不应该工作,但似乎只要你没有像以前那样超过内核缓冲区(我在之前的程序中完成了它)。

所以我想,如果你想要平台无关的多处理日志记录,你可以使用套接字并在每个fork之后创建一个新的SocketHandler,以便像Vinay在下面建议的那样安全(这应该适用于所有地方)。对我来说,由于我可以很好地控制运行我的软件的操作系统,我认为我将使用一个带有FileHandler的全局log对象(默认情况下以附加模式打开,并且大多数都是缓冲行) OSS)。 open的文档说“负缓冲意味着使用系统默认值,通常为tty设备进行行缓冲,并为其他文件完全缓冲。如果省略,则使用系统默认值。”或者我可以创建自己的日志记录流以确保线路缓冲。为了清楚起见,我很满意:

# Process A
a_file.write("A\n")
a_file.write("A\n")
# Process B
a_file.write("B\n")

...的制造

A\n
B\n
A\n

只要它不产生......

AB\n
\n
A\n

Vinay (或其他任何人),我有多难?让我知道。感谢您提供更多清晰/可靠性。

1 个答案:

答案 0 :(得分:2)

  

我需要在每个os.fork()之后创建一个新的日志对象吗?现有的全局日志对象会发生什么?

AFAIK全局日志对象仍然指向父进程和子进程中的同一记录器。所以你不需要创建一个新的。但是,我认为您应该在SocketHandler中的fork()之后创建并添加monitor(),以便套接字服务器具有四个不同的连接,每个子进程一个。如果你不这样做,那么在monitor()中分叉的子进程将从它们的父进程继承SocketHandler及其套接字句柄,但我不确定它是否会出错。这种行为很可能取决于操作系统,你可能在OSX上很幸运。

  

按照我的方式做事,我是否能解决我想避免的问题(多个打开的文件/套接字)?这会失败,为什么会失败(我希望能够判断未来类似的实现是否会失败)?

如上所述,如果你在最后fork()之后创建套接字服务器的套接字连接,我不会指望失败,但我不确定在任何其他情况下这种行为都是明确定义的。你引用了多个打开的文件,但是我没有看到你在伪代码片段中打开文件的引用,只是打开套接字。

  

此外,从多个进程登录到一个文件的“正常”(one log = expression)方法以何种方式失败?它是否引发IOError / OSError?或者它只是没有完全将数据写入文件?

我认为行为没有明确定义,但人们会期望失败模式呈现为来自文件中不同进程的散布日志消息,例如

Process A writes first part of its message
Process B writes its message
Process A writes second part of its message

更新:如果您按照评论中描述的方式使用FileHandler,由于我上面描述的方案,过程不会那么好:进程A和B都开始指向文件的末尾(因为附加模式),但之后事情可能会失去同步,因为(例如在多处理器上,但甚至可能在单处理器上),一个进程可以(抢占另一个和)写入另一个进程完成之前的共享文件句柄。