app*_*orc 6 python logging atomic multiprocessing atomicity
我花了几个小时来研究行为,首先是关于这些问题:
看来,如果在打开文件时使用'O_APPEND'标志,则在Linux上从多个进程登录到同一文件总是可以的。而且我相信python肯定会在其日志记录模块中使用'O_APPEND'标志。
并通过一个小测试:
#!/bin/env python
import os
import logging
logger = logging.getLogger('spam_application')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
logger.addHandler(fh)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
for i in xrange(10000):
p = os.getpid()
logger.debug('Log line number %s in %s', i, p)
Run Code Online (Sandbox Code Playgroud)
我用它运行:
./test.py & ./test.py & ./test.py & ./test.py &
Run Code Online (Sandbox Code Playgroud)
我发现spam.log中没有错。此行为可能支持上述结论。
但是问题来了:
最后,如果两个进程正在同一文件上执行写操作,那是指它们正在调用同一文件上的write(2),谁可以确保来自两个进程的数据不会交织(内核或文件系统?),以及如何交织。[注意:我只想深入了解写系统调用,对此的任何欢迎。
编辑1:
难道这和这只是存在有不同的操作系统环境之间的兼容性,如Windows,Linux或Mac?
编辑2:
再进行一次测试,每次将8KB字符串提供给logging.debug。这次我可以在spam.log中看到“交错”行为。此行为正是在上一页中指定的关于PIPE_BUF的行为。因此,似乎在Linux上的行为很明显,如果write(2)的大小小于PIPE_BUF,则使用O_APPEND是可以的。
我越挖越深。现在我想这些事实已经很清楚了:
\n\n使用 O_APPEND,多个进程的并行 write(2) 就可以了。只是行的顺序未确定,但行不会相互交错或覆盖。根据 Niall Douglas 对Understanding并发文件写入来自多个进程的回答,数据的大小是任意数量的。我已经在Linux上对此进行了“任意数量”的测试,但没有找到上限,所以我想这是正确的。
没有O_APPEND,就会乱七八糟。POSIX 是这样说的:“POSIX.1-2008 的本卷没有指定从多个进程并发写入文件的行为。应用程序应该使用某种形式的并发控制。”
现在我们进入Python。我在 EDIT3 中进行的测试,即 8K,我找到了它的起源。Python的write()实际上使用fwrite(3)\xef\xbc\x8c,我的python在这里设置了一个BUFF_SIZE,即8192。根据abarnert在Linux上文件的默认缓冲区大小中的回答。这个8192的故事说来话长。
不过,欢迎提供更多信息。
\n我不会在这里依赖测试。奇怪的事情只能在竞争条件下发生,并且通过测试展示竞争条件几乎没有意义,因为竞争条件不太可能发生。因此它可以很好地进行 1000 次测试运行,并在稍后的产品中随机中断......您引用的页面说:
不支持从多个进程记录到单个文件,因为 Python 中没有跨多个进程序列化对单个文件的访问的标准方法
这并不意味着它会崩溃......它甚至在特定文件系统上的特定实现中是安全的。这只是意味着它可能会在任何其他版本的 Python 或任何其他文件系统上崩溃,而没有任何修复的希望。
如果您确实想确保这一点,则必须深入研究 Python 源代码(针对您的版本)来控制日志记录的实际实现方式,并控制它在您的文件系统上是否安全。并且您将始终受到日志模块中的后续优化打破您的假设的可能性的威胁。
恕我直言,这就是 Logging Cookbook 中发出警告的原因,并且存在一个特殊模块来允许并发记录到同一文件。最后一个不依赖于任何未指定的内容,而只是使用显式锁定。
| 归档时间: |
|
| 查看次数: |
2343 次 |
| 最近记录: |