4

我有一个与配置文件交互的库。导入库时,初始化代码会读取配置文件,可能会对其进行更新,然后将更新后的内容写回文件中(即使没有任何更改)。

非常偶尔,我会遇到配置文件内容消失的问题。具体来说,当我连续数千次运行短脚本(使用库)多次调用时,就会发生这种情况。它从不在同一个目录中发生,这让我相信这是一个有点随机的问题——特别是 IO 的竞争条件。

调试起来很痛苦,因为我永远无法可靠地重现问题,而且它只发生在某些系统上。我怀疑可能会发生什么,但我想看看我在 Python 中的文件 I/O 图像是否正确。

所以问题是,Python 程序什么时候真正将文件内容写入磁盘?我认为在文件关闭时内容会进入磁盘,但后来我无法解释这个错误。当 python 关闭一个文件时,它会将内容刷新到磁盘本身,还是简单地将其排队到文件系统?Python终止后文件内容是否可以写入磁盘?我可以通过使用fp.flush(); os.fsync(fp.fileno())fp文件句柄在哪里)来避免这个问题吗?

如果重要的话,我正在 Unix 系统(特别是 Mac OS X)上编程。编辑:另外,请记住,这些进程不是同时运行的。

附录:这是我怀疑的具体竞争条件:

  1. 进程#1 被调用。
  2. 进程 #1 以读取模式打开配置文件,完成后将其关闭。
  3. 进程 #1 以写入模式打开配置文件,擦除其所有内容。内容的擦除同步到磁盘。
  4. 进程#1 将新内容写入文件句柄并关闭它。
  5. 过程#1:关闭文件后,Python 告诉操作系统排队将这些内容写入磁盘。
  6. 进程#1 关闭并退出
  7. 进程 #2 被调用
  8. 进程 #2 以读取模式打开配置文件,但尚未同步新内容。进程#2 看到一个空文件。
  9. 在进程 2 读取文件后,操作系统终于完成了将内容写入磁盘
  10. 过程#2,认为文件是空的,设置配置文件的默认值。
  11. 进程#2 将其配置文件版本写入磁盘,覆盖最后一个版本。
4

1 回答 1

2

几乎可以肯定这不是 python 的错。如果 python 关闭文件,或者干净地退出(而不是被信号杀死),那么操作系统将拥有文件的新内容。任何后续打开都应返回新内容。一定有更复杂的事情发生。这里有一些想法。

  1. 您所描述的听起来更有可能是文件系统错误而不是 Python 错误,而且文件系统错误不太可能。

  2. 如果您的文件实际上驻留在远程文件系统中,则文件系统错误的可能性要大得多。他们有吗?

  3. 所有进程都使用同一个文件吗?对文件执行“ls -li”以查看其 inode 编号,并查看它是否会更改。在您的情况下,它不应该。是否有可能正在移动文件、移动目录或删除目录并重新创建它们?是否涉及符号链接?

  4. 您确定程序的运行没有重叠吗?它们中的任何一个是否从末尾带有“&”的外壳运行(即在后台)?这很容易意味着在第一个完成之前开始第二个。

  5. 是否有其他程序写入同一文件?

  6. 这不是您的问题,但是如果您需要原子更改(以便任何并行运行的程序只能看到旧版本或新版本,而不是空文件),实现它的方法是将新内容写入另一个文件(例如“foo.tmp”),然后执行 os.rename("foo.tmp", "foo")。重命名是原子的。

于 2013-06-11T02:53:47.270 回答