【问题标题】:How can I speed up this directory walk?我怎样才能加快这个目录遍历?
【发布时间】:2020-09-24 17:48:19
【问题描述】:

我正在尝试编写一个函数,该函数通过遍历下面带有os.walk() 的目录树来查找目录。在我的机器上,这需要 15 秒。

for dir_path, dir_names, filenames in os.walk(os.path.expanduser('~')):
    for dir_name in dir_names:
        if dir_name == 'some_dir':
            path = os.path.join(dir_path, dir_name)
            print(path)

我读到os.scandir() 更快,所以我在下面尝试了这个,尽管我认为实现是错误的。它有效,但现在将近 30 秒。

for dir_path, dir_names, filenames in os.walk(os.path.expanduser('~')):
    with os.scandir(dir_path) as entries:
        for entry in entries:
            if entry.name.endswith('some_dir') and entry.is_dir():
                print(entry.path)

如何加快速度?

【问题讨论】:

  • os.scandir() 需要使用而不是 os.walk(),如果您希望它有机会让任何事情变得更快。使用它另外意味着您从操作系统加载名称两次——一次从具有通常性能的os.walk(),另一次从os.scandir()
  • @CharlesDuffy 据我所知,os.scandir()os.listdir() 的替代品,因此它返回一个遍历目录元素的迭代器,但不是递归的。所以如果替换os.walk(),它只会返回home文件夹中的元素,而不是子目录中的元素。
  • 对,所以你需要多次调用它,每个目录一次被递归到 - 就像 os.walk() 在幕后所做的那样。而如果你的 Python 版本有一个 os.walk() 使用 scandir 而不是 listdir 已经开箱即用,那么那里可能没有太多额外的空间。
  • 进行完整目录扫描总是很慢——这就是为什么人们通常更喜欢在可行的情况下使用locate 而不是findfind 在底层做了很多棘手的低级优化。
  • ...如果some_dir 最有可能出现的位置有限,我强烈建议您编写能够意识到这一点的代码并在回退到更广泛的扫描之前优先考虑这些位置(如果不只是要求用户告诉你你需要的资源在哪里,这并不是闻所未闻或罕见的)。

标签: python os.walk scandir


【解决方案1】:

一个建议是替换 for dir_name in dir_names 部分:

for dir_path, dir_names, filenames in os.walk(os.path.expanduser('~'):
    if 'some_dir' in dir_names:
        path = os.path.join(dir_path, 'some_dir')
        print(path)

我不知道你是否有很多子目录,但根据这一点,这应该已经使代码更快了。

另外,我建议把这个注释掉

os.scandir() 函数优于 os.listdir,当您需要文件类型的其他信息时,但由于 dir_names 仅包含子文件夹的目录,这是调用该函数产生的额外开销,因此它比原始代码慢很多。

如果您使用 python 版本>=3.5,那么os.walk() 已经在后台调用了os.scandir()。正如 Charles Duffy 已经提到的,以递归方式单独调用 os.scandir() 很可能不会快很多。

【讨论】:

  • 你说得对,for dir_name in dir_names 是多余的,但删除此行并没有显示任何速度提升。
  • 那么我建议你阅读 Charles 的 cmets。例如,如果'some_dir' 目录仅位于['Documents', 'Downloads', 'data'] 之一中,那么仅os.walk() 覆盖它们可能会快得多,而不是整个home 文件夹。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 2021-08-01
  • 1970-01-01
  • 2012-11-03
  • 2011-09-27
  • 2021-07-31
相关资源
最近更新 更多