我花了几个小时来挖掘这种行为,首先是关于这些问题:
- `write(2)` 到本地文件系统的原子性 https://stackoverflow.com/questions/10650861/atomicity-of-write2-to-a-local-filesystem
- 如何同步(使原子化)从两个进程写入一个文件? https://stackoverflow.com/questions/6896011/how-can-i-synchronize-make-atomic-writes-on-one-file-from-from-two-process
- 如何以编程方式确定“写入”系统调用对特定文件是否是原子的? https://stackoverflow.com/questions/7660293/how-does-one-programmatically-determine-if-write-system-call-is-atomic-on-a-pa
- 如果两个不同的进程同时对同一文件调用写入系统调用,会发生什么情况 https://stackoverflow.com/questions/7236475/what-happens-if-a-write-system-call-is-called-on-same-file-by-2-different-proces
- http://article.gmane.org/gmane.linux.kernel/43445 http://article.gmane.org/gmane.linux.kernel/43445
看来如果我们在打开文件时使用“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)
我运行它:
./test.py & ./test.py & ./test.py & ./test.py &
我发现spam.log没有任何问题。这种行为或许可以支持上面的结论。
但问题随之而来:
- 这是什么意思here https://docs.python.org/2/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes?
- 以及使用场景有哪些this https://pypi.python.org/pypi/ConcurrentLogHandler/0.9.1,只是为了文件轮换?
最后,如果两个进程正在同一个文件上进行写入,我的意思是它们正在同一个文件上调用 write(2),谁确保来自两个进程的数据不会交错(内核或文件系统?),以及如何交错。[注意:我只是想深入了解 write 系统调用,欢迎任何有关此的点击。]
EDIT1 :
Do this https://docs.python.org/2/howto/logging-cookbook.html#logging-to-a-single-file-from-multiple-processes and this https://pypi.python.org/pypi/ConcurrentLogHandler/0.9.1只是为了不同操作系统环境(如 Windows、Linux 或 Mac)之间的兼容性而存在?
EDIT2 :
再进行一项测试,每次向logging.debug提供8KB字符串。这次我可以在 spam.log 中看到“交错”行为。
此行为正是上面一页中有关 PIPE_BUF 的指定内容。所以看起来 Linux 上的行为很清楚,如果 write(2) 的大小小于 PIPE_BUF,则使用 O_APPEND 是可以的。