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

时间:2016-07-06 08:32:19

标签: python logging multiprocessing atomic 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)

我用它来运行:

./test.py & ./test.py & ./test.py & ./test.py &

我发现spam.log没有任何问题。这种行为可能会支持上述结论。

但问题来了:

  • 这是什么意思here
  • 使用this的场景是什么,仅用于文件轮换?

最后,如果两个进程正在对同一个文件进行写操作,我的意思是他们在同一个文件上调用write(2),确保来自两个进程的数据不交错(内核或文件系统?),以及如何。[注意:我只是想深入了解写入系统调用,欢迎任何关于此事的热门。]

EDIT1:

是否只存在thisthis以实现不同操作系统之间的兼容性,例如windows,linux或mac?

EDIT2:

再一次测试,每次向logging.debug提供8KB字符串。这次我可以在spam.log中看到“交错”行为。 此行为正是上面一页中有关PIPE_BUF的内容。因此,似乎linux上的行为很明显,如果写入(2)的大小小于PIPE_BUF,则使用O_APPEND即可。

3 个答案:

答案 0 :(得分:2)

我越陷越深。现在我认为这些事实很清楚:

  1. 使用O_APPEND,来自多个进程的并行写入(2)是可以的。它的线条顺序尚未确定,但线条不会相互交错或覆盖。根据Niall Douglas对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.根据来自Default buffer size for a file on Linux的abarnert的回答。这个8192有很长的故事。

  4. 但是,欢迎提供更多信息。

答案 1 :(得分:1)

我不会依赖这里的测试。奇怪的事情只能在竞争条件下发生,并且通过测试表现出竞争条件几乎是没有意义的,因为竞争条件不太可能发生。因此,它可以很好地用于1000次测试运行并随后在产品中随机中断...您引用的页面说:

  

多个进程记录到单个文件不支持,因为没有标准方法可以在Python中跨多个进程序列化对单个文件的访问

这并不意味着它会破坏......它甚至可以在特定文件系统的特定实现中安全。它只是意味着它可以破解而无需修复任何其他版本的Python或任何其他文件系统。

如果你真的想确定它,你将不得不深入研究Python源代码(对于你的版本)来控制实际实现日志记录的方式,并控制它是否对你的文件系统是安全的。并且您将始终受到日志记录模块中的后续优化破坏您的假设的可能性的威胁。

恕我直言,这是Logging Cookbook中警告的原因,以及是否存在允许并发记录到同一文件的特殊模块。最后一个不依赖于任何未指定的内容,而只是使用显式锁定。

答案 2 :(得分:0)

我尝试过类似的代码(我在python 3中尝试过)

import { Component, AfterViewInit, Renderer2 } from '@angular/core';


@Component({...})
export class ChildComponent implements AfterViewInit {

  sFragment: string;

  constructor(private renderer: Renderer2) {}

  ngAfterViewInit(): void {
      this.sFragment = 'footerWrapperTop';

      const element = this.renderer.selectRootElement(`#${this.sFragment}`, true); // true to indicate that you will preserve the content

      element.scrollIntoView({ behavior: 'smooth' });   // for smooth scrolling

  }

}

这对我来说完全正常,类似issue的问题在这里解决。

这花费了很多Cpu时间,但没有占用内存。

编辑:
正常表示所有请求的内容均已记录,但订单丢失。因此竞赛条件仍未解决,