我一直在从事一个必须创建大型目录结构的项目。我的第一个解决方案是保留所有存在的目录的字典,如果遇到尚未创建的目录,请使用 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 倍的时间(94 秒而不是 24 秒)。它不明白为什么这个函数从我的函数调用时比它被 os.makedirs() 调用时花费更长的时间。 有人知道为什么吗?
最佳答案
你是对的,os.mkdirs 在创建目录之前检查路径组件的存在 see here, line 136 .您的代码和 os.mkdirs 都使用了 c-python 模块 posixmodule.c对于 mkdir 的实际实现,它在 Linux 上解析为系统调用 mkdir。
鉴于 stat 非常耗时,看起来 os.mkdir 确实没有必要统计,因为如果“a”不存在,那么肯定“a/b”也不存在。
使用 strace可以看出,两个实现调用 mkdir 的次数相同,但是当路径是相对路径时,您创建的函数无论如何都会构造绝对路径,而 os.mkdirs 使用相对路径。
一个可能性是,额外的时间是操作系统搜索目录结构以找到正确的目录,而不是每次都添加到“。”
操作系统.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 或您的源调用 mkdir 所花费的时间(使用 cProfile)大致相同
操作系统.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中的new source花费了大量的时间
4000 0.104 0.000 1.003 0.000 posixpath.py:400(relpath)
也许这是分析方法或安装的精妙之处。
关于python - 为什么 os.mkdir() 在显式调用时变慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21442479/