Python日志记录支持多处理吗?

2022-04-10 00:00:00 python python-multiprocessing

问题描述

我被告知在多处理中不能使用日志记录。您必须执行并发控制,以防多处理扰乱日志。

但是我做了一些测试,在多处理中使用日志似乎没有问题

import time
import logging
from multiprocessing import Process, current_process, pool


# setup log
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='/tmp/test.log',
                    filemode='w')


def func(the_time, logger):
    proc = current_process()
    while True:
        if time.time() >= the_time:
            logger.info('proc name %s id %s' % (proc.name, proc.pid))
            return



if __name__ == '__main__':

    the_time = time.time() + 5

    for x in xrange(1, 10):
        proc = Process(target=func, name=x, args=(the_time, logger))
        proc.start()

如您从代码中所见。

我故意让子进程在同一时刻(启动后5秒)写入日志,以增加冲突的可能性。但根本没有冲突。

所以我的问题是我们可以在多处理中使用日志记录吗? 为什么这么多帖子说我们不能?


解决方案

正如马蒂诺正确解释的那样:登录多进程设置是不安全的,因为多个进程(对现有的其他进程一无所知)正在写入同一文件,可能会相互干扰。

现在发生的情况是,每个进程都持有一个打开的文件句柄,并对该文件执行"追加写入"。问题是在什么情况下追加写入是"原子的"(也就是说,不能被写入同一文件并混合其输出的另一个进程中断)。这个问题适用于每种编程语言,因为最终它们会对内核进行系统调用。This answer回答在哪些情况下可以使用共享日志文件。

归根结底是检查您的管道缓冲区大小,在/usr/include/linux/limits.h中定义的Linux上是4096字节。对于其他操作系统,here是一个很好的列表。

这意味着:如果您的日志行少于4‘096个字节(如果在Linux上),则附加是安全的,如果磁盘是直接连接的(即,在两者之间没有网络)。但更多细节请查看我答案中的第一个链接。要测试这一点,您可以使用不同的长度执行logger.info('proc name %s id %s %s' % (proc.name, proc.pid, str(proc.name)*5000))。以5000为例,我已经在/tmp/test.log中混淆了日志行。

在this question中已经有相当多的解决方案,因此我不在此添加我自己的解决方案。

更新:烧瓶和多进程

像FASK这样的Web框架如果由uwsgi或nginx托管,将在多个工作进程中运行。在这种情况下,多个进程可能会写入一个日志文件。会有问题吗?

烧瓶中的错误处理是通过stdout/stderr完成的,然后由Web服务器(uwsgi、nginx等)接收。它需要注意以正确的方式写入日志(例如,参见[this flASK+nginx示例])(http://flaviusim.com/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/),可能还会添加进程信息,以便您可以将错误行关联到进程。发件人:flasks doc:

默认情况下,从Flask0.11开始,错误会自动记录到您的Web服务器的日志中。但是,警告并非如此。

因此,如果您使用warn并且消息超过管道缓冲区大小,您仍然会遇到日志文件混合的问题。

相关文章