代码之家  ›  专栏  ›  技术社区  ›  Noah

os.path.exists()谎言

  •  9
  • Noah  · 技术社区  · 14 年前

    我在Linux集群上运行了许多python脚本,一个作业的输出通常是另一个脚本的输入,可能在另一个节点上运行。我发现在python注意到在其他节点上创建的文件之前存在一些不重要的延迟——os.path.exists()返回false,open()也会失败。我可以做一个while not os.path.exists(mypath)循环,直到文件出现,它可能需要一整分钟以上,这在一个有许多步骤的管道中不是最佳的,并且可能并行运行许多数据集。

    到目前为止,我找到的唯一解决方法是调用subprocess.popen(“ls%s”%(pathdir),shell=true),它可以神奇地解决问题。我认为这可能是一个系统问题,但python可能以任何方式导致了这一问题?什么缓存之类的?到目前为止,我的系统管理员帮不了什么忙。

    2 回复  |  直到 9 年前
        1
  •  10
  •   Charles Clayton    9 年前

    os.path.exists() 打电话给C图书馆 stat() 功能。

    我相信您在内核的NFS实现中遇到了一个缓存。下面是一个指向描述问题的页面的链接,以及一些刷新缓存的方法。

    文件句柄缓存

    目录将文件名缓存到文件句柄映射。最常见的问题是:

    您有一个打开的文件,您需要检查该文件是否已被新文件替换。在stat()返回新文件的信息而不是打开的文件之前,必须刷新父目录的文件句柄缓存。

    实际上,本例还有另一个问题:旧文件可能已被删除并替换为新文件,但两个文件可能具有相同的inode。您可以通过刷新打开文件的属性缓存,然后查看fstat()是否使用estale失败来检查这种情况。

    您需要检查文件是否存在。例如,一个锁文件。内核可能缓存了该文件不存在的情况,即使事实上它确实存在。您必须刷新父目录的负文件句柄缓存,以查看文件是否真的存在。

    刷新文件句柄缓存的几种方法:

    如果父目录的mtime更改了,则通过刷新其属性缓存来刷新文件句柄缓存。如果NFS服务器支持纳秒或微秒分辨率,这应该会非常好地工作。

    _、linux:chown()当前所有者的目录。如果调用成功返回,将刷新文件句柄缓存。

    _、Solaris 9,10:唯一的方法是尝试rmdir()父目录。“无诱惑”意味着缓存已刷新。尝试rmdir()时,当前目录的eival失败,无法刷新缓存。

    __freebsd 6.2:唯一的方法是尝试rmdir()父目录或其下的文件。enotty、enotdir和eacces失败意味着缓存被刷新,但enont没有刷新。freebsd不缓存负条目,因此不必刷新它们。

    http://web.archive.org/web/20100912144722/http://www.unixcoding.org/NFSCoding

        2
  •  1
  •   jathanism    14 年前

    这个问题与Python进程在自己的shell中运行的事实有关。当你奔跑 subprocess.Popen(shell=True) 你正在生成一个新的外壳,它可以解决你所遇到的问题。

    python没有引起这个问题。它结合了Linux中的nfs(文件存储)和目录列表的功能。