【问题标题】:Can I use a StreamHandler for Logging in a Multiprocessing Environment in Python?我可以在 Python 的多处理环境中使用 StreamHandler 进行日志记录吗?
【发布时间】:2015-03-10 16:23:24
【问题描述】:

在多处理环境中使用单个 StreamHandler 是否安全?

更准确地说,只有一个StreamHandler 将所有进程的日志记录语句打印到stdout 会不会有问题?比如这样:

import multiprocessing as mp
import logging


def do_log(no):
    # 2nd EDIT, suppose we do also this,
    # which should not have any effect if there already exists a 
    # handler! But it probably has under Windows:
    format = '%(processName)-10s %(name)s %(levelname)-8s %(message)s'
    # This creates a StreamHandler
    logging.basicConfig(format=format, level=logging.INFO)

    # root logger logs Hello World
    logging.getLogger().info('Hello world {}'.format(no))


def main():
    format = '%(processName)-10s %(name)s %(levelname)-8s %(message)s'
    # This creates a StreamHandler
    logging.basicConfig(format=format, level=logging.INFO)

    n_cores = 4
    pool = mp.Pool(n_cores)
    # Log to stdout 100 times concurrently
    pool.map(do_log, range(100))
    pool.close()
    pool.join()


if __name__ == '__main__':
    main()

这将打印如下内容:

ForkPoolWorker-1 root INFO     Hello world 0
ForkPoolWorker-3 root INFO     Hello world 14
ForkPoolWorker-3 root INFO     Hello world 15
ForkPoolWorker-3 root INFO     Hello world 16
...

这是一个安全的设置吗?如果不是,会出现什么问题?有什么更严重的 而不是乱码的控制台输出,即程序崩溃?

如果安全的话,使用mp.Process 代替mp.Pool 是否仍然安全?

编辑:我的问题涉及任何操作系统,所以如果 Linux、OSX 或 Windows 之间存在差异,请随时告诉我。

第二次编辑:好的,所以在 Windows 下处理程序消失了,如果我们为每个进程创建一个新的 StreamHandler 会发生什么?

【问题讨论】:

  • 我看过这部作品的形式有限。我原以为会发生的最糟糕的情况是来自不同进程的某些行可能会交错,而在其他情况下(不是专门针对 Python),如果系统负载过重,这种情况往往会发生。抱歉,这只是一个轶事答案。

标签: python logging multiprocessing stdout


【解决方案1】:

此代码在 Windows 上根本不起作用,这对您来说可能是也可能不是问题。由于 Windows 没有fork,因此您在父级中进行的记录器自定义不会被子级正确继承。

在 Linux/OS X 上,唯一的问题是来自不同进程的消息会出现乱码。 multiprocessing 文档mentions that when discussing logging

提供了一些对日志记录的支持。但是请注意,logging 包不使用进程共享锁,所以它是可能的(取决于 在处理程序类型上)用于获取来自不同进程的消息 搞混了。

mp.Pool 是使用 mp.Process 实现的,因此它们在此处的行为将完全等效。

编辑:

如果您想要在 Windows 上也可以运行的基本等效的东西,您需要在每个子进程以及父进程中运行日志记录配置:

import multiprocessing as mp
import logging


def do_log(no):
    # root logger logs Hello World
    logging.getLogger().info('Hello world {}'.format(no))

def init_log():
    fmt = '%(processName)-10s %(name)s %(levelname)-8s %(message)s'
    logging.basicConfig(format=fmt, level=logging.INFO)

def main():
    # This creates a StreamHandler
    init_log()
    n_cores = 4
    pool = mp.Pool(n_cores, initializer=init_log)
    # Log to stdout 100 times concurrently
    pool.map(do_log, range(100))
    pool.close()
    pool.join()


if __name__ == '__main__':
    main()
    logging.getLogger().info("hi")

这为您提供了与原始版本在 Linux 上相同的问题(日志消息会出现乱码)。

【讨论】:

  • 嗯,好的,到目前为止一切顺利。如果我在 windows 下为每个进程创建一个新的 StreamHandler 会发生什么? (见编辑)
  • 我不是故意要编辑这么多,但是这个问题突然出现在我的脑海中,我不想再问其他问题了。如果 Windows 阻止继承 StreamHandler,如果我们为上面的每个进程创建一个新的 StreamHanlder 会发生什么?
  • @SmCaterpillar 查看我的编辑。你得到的东西基本上等同于 Linux 上的原始版本。每个进程都会写入标准输出,但进程之间没有序列化,这意味着如果进程同时写入,您将收到乱码。
  • 谢谢!他们出现乱码的可能性有多大?仅适用于大消息?因为小的立刻冲掉?
  • @SmCaterpillar 在 Windows 上,示例代码每次运行时都会出现部分乱码输出。它永远不会在 Linux 上出现乱码,尽管我不确定具体原因。我不认为 Python 在做什么,所以你可能不应该依赖它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多