为什么显式调用时os.mkdir()会变慢?

时间:2014-01-29 20:57:26

标签: python linux python-2.7 operating-system

我一直在做一个必须创建大型目录结构的项目。我的第一个解决方案是保留一个存在的所有目录的字典,如果遇到一个尚未制作的目录,则使用os.makedirs()创建它和任何缺少的中间人。 当我分析这段代码时,我发现大部分时间(132秒中有105秒)花在调用posix.stat()来确定中间目录不存在。但是我在一个空目录中构建整个结构,所以我已经知道没有任何中间目录存在。

为了利用这一点,我编写了一个代码版本,该代码保留了内部备忘录,描述了目录树的结构,以便它可以在不查询操作系统的情况下确定创建了哪些目录:

class DirTree:
  def __init__(self, root):
    self.root = os.path.abspath(root)
    self.tree = {}
  def makedirs(self, path):
    relpath = os.path.relpath(path, self.root).replace('\\', '/')
    built = self.root
    node = self.tree
    for directory in relpath.split('/'):
        built = os.path.join(built, directory)
        if directory in node:
            node = node[directory]
        else:
            node[directory] = {}
            node = node[directory]
            os.mkdir(built, 0777)

这段代码确实运行得更快,但是当我通过探查器运行它时,对os.mkdir()的4068次调用现在需要4倍(94s而不是24s)。它不明白为什么这个函数在调用我的函数时需要的时间比os.makedirs()调用时要长。 有谁知道为什么?

1 个答案:

答案 0 :(得分:1)

你是对的,os.mkdirs在创建目录see here, line 136之前检查路径组件的存在。你的代码和os.mkdirs都使用c-python模块posixmodule.c来实现mkdir的实现,在Linux上它解析为系统调用mkdir。

看起来os.mkdir真的是统计数据,因为stat非常耗时,因为如果“a”不存在,那么肯定“a / b”也不存在。

使用strace可以看出两个实现调用mkdir的次数相同,但是当路径是相对的时,你创建的函数构造绝对路径而不是使用相对路径的os.mkdirs。 / p>

一种可能性是额外的时间是操作系统搜索目录结构以找到正确的目录而不是每次都添加到“。”

os.mkdirs

stat("a/b/c", 0x7fff34b1c4d0)           = -1 ENOENT (No such file or directory)
stat("a/b", 0x7fff34b1c260)             = -1 ENOENT (No such file or directory)
stat("a", 0x7fff34b1bff0)               = -1 ENOENT (No such file or directory)
mkdir("a", 0777)                        = 0
mkdir("a/b", 0777)                      = 0
mkdir("a/b/c", 0777)                    = 0
mkdir("a/b/c/d", 0777)                  = 0

修改过的mkdirs

mkdir("/tmp/a", 0777)                   = 0
mkdir("/tmp/a/b", 0777)                 = 0
mkdir("/tmp/a/b/c", 0777)               = 0
mkdir("/tmp/a/b/c/d", 0777)             = 0

话虽如此,我无法重现你的结果。我发现os.mkdirs或你的来源调用的时间(使用cProfile)mkdir大致相同

os.mkdirs

 4003    0.132    0.000    0.132    0.000 {posix.mkdir}

修改过的mkdirs

 4003    0.147    0.000    0.147    0.000 {posix.mkdir}

但是在posixpath

中花费了大量时间在新来源中
 4000    0.104    0.000    1.003    0.000 posixpath.py:400(relpath)

也许这是分析方法或安装细微方法的工件。