如果我从 python 中的多个不同进程登录到同一个文件,会发生什么?

2024-05-06

我花了几个小时来挖掘这种行为,首先是关于这些问题:

  • `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 是可以的。


我越挖越深。现在我想这些事实已经很清楚了:

  1. 使用 O_APPEND,多个进程的并行 write(2) 就可以了。只是行的顺序未确定,但行不会相互交错或覆盖。根据尼尔·道格拉斯 (Niall Douglas) 的回答,数据的大小是任意数量的了解多个进程的并发文件写入 https://stackoverflow.com/questions/12942915/understanding-concurrent-file-writes-from-multiple-processes。我已经在linux上对此进行了“任意数量”的测试,但没有找到上限,所以我想这是正确的。

  2. 没有O_APPEND,就会乱七八糟。 POSIX 是这样说的:“POSIX.1-2008 的本卷没有指定从多个进程并发写入文件的行为。应用程序应该使用某种形式的并发控制。”

  3. 现在我们进入Python。我在 EDIT3 中进行的测试,即 8K,我找到了它的起源。 Python的write()实际上使用了fwrite(3),而我的python在这里设置了一个BUFF_SIZE,即8192。根据abarnert的回答Linux 上文件的默认缓冲区大小 https://stackoverflow.com/questions/18194374/default-buffer-size-for-a-file。这个8192的故事说来话长。

不过,欢迎提供更多信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果我从 python 中的多个不同进程登录到同一个文件,会发生什么? 的相关文章

随机推荐