Python日志记录支持多处理吗?
问题描述
我被告知在多处理中不能使用日志记录。您必须执行并发控制,以防多处理扰乱日志。
但是我做了一些测试,在多处理中使用日志似乎没有问题
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
并且消息超过管道缓冲区大小,您仍然会遇到日志文件混合的问题。
相关文章