【问题标题】:Quicker to os.walk or glob?os.walk 还是 glob 更快?
【发布时间】:2012-02-14 09:50:13
【问题描述】:

我在一个大硬盘上用 python 查找文件。我一直在看 os.walk 和 glob。我通常使用 os.walk,因为我发现它更整洁而且似乎更快(对于通常大小的目录)。

有没有人对这两种方法都有经验,可以说哪个更有效?正如我所说,glob 似乎更慢,但你可以使用通配符等,就像 walk 一样,你必须过滤结果。这是查找核心转储的示例。

core = re.compile(r"core\.\d*")
for root, dirs, files in os.walk("/path/to/dir/")
    for file in files:
        if core.search(file):
            path = os.path.join(root,file)
            print "Deleting: " + path
            os.remove(path)

或者

for file in iglob("/path/to/dir/core.*")
    print "Deleting: " + file
    os.remove(file)

【问题讨论】:

  • 对我来说听起来像是过早的优化。我浏览了源代码(hg.python.org/cpython/file/d01208ba482f/Lib/glob.pyhg.python.org/cpython/file/d01208ba482f/Lib/os.py),发现这两个函数都依赖于 os.listdiros.isdir,所以我的直觉告诉我,你不会以任何方式获得太多收益。 (但是,正如下面两个答案中所指出的,os.walk 会在子目录上递归,而glob.iglob 不会,因此比较没有意义)。如果您确实遇到了性能问题,请介绍几种方法。否则,只需编写清晰的代码即可。

标签: python traversal glob os.walk directory-walk


【解决方案1】:

我对 1000 个目录中的一小部分网页缓存进行了研究。任务是计算目录中的文件总数。输出是:

os.listdir: 0.7268s, 1326786 files found
os.walk: 3.6592s, 1326787 files found
glob.glob: 2.0133s, 1326786 files found

如您所见,os.listdir 是三个中最快的。对于这个任务,glog.glob 仍然比 os.walk 快。

来源:

import os, time, glob

n, t = 0, time.time()
for i in range(1000):
    n += len(os.listdir("./%d" % i))
t = time.time() - t
print "os.listdir: %.4fs, %d files found" % (t, n)

n, t = 0, time.time()
for root, dirs, files in os.walk("./"):
    for file in files:
        n += 1
t = time.time() - t
print "os.walk: %.4fs, %d files found" % (t, n)

n, t = 0, time.time()
for i in range(1000):
    n += len(glob.glob("./%d/*" % i))
t = time.time() - t
print "glob.glob: %.4fs, %d files found" % (t, n)

【讨论】:

【解决方案2】:

*, ?, and character ranges expressed with [] will be correctly matched. This is done by using the os.listdir() and fnmatch.fnmatch() functions

我认为即使使用 glob,您仍然需要 os.walk,除非您直接知道您的子目录树有多深。

顺便说一句。在glob documentation 中它说:

"*、? 和用 [] 表示的字符范围将正确 匹配。这是通过使用 os.listdir() 和 fnmatch.fnmatch() 函数"

我会选择一个

for path, subdirs, files in os.walk(path):
        for name in fnmatch.filter(files, search_str):
            shutil.copy(os.path.join(path,name), dest)

【讨论】:

    【解决方案3】:

    在测量/分析之前不要浪费时间进行优化。专注于使您的代码简单且易于维护。

    例如,在您的代码中,您预编译 RE,这不会给您带来任何速度提升,因为 re 模块具有内部预编译 RE 的 re._cache

    1. 保持简单
    2. 如果它很慢,那么配置文件
    3. 一旦您确切知道需要优化的内容,请进行一些调整并始终记录下来

    请注意,与“未优化”的代码相比,几年前进行的一些优化会使代码运行速度变慢。这尤其适用于基于 JIT 的现代语言。

    【讨论】:

    • -1。 OP提到了一个“大磁盘”。此外,代码显然已经很简单了。此外,OP似乎处于优化阶段。用诸如“过早的优化是 blabla 的根源”(实际上是 Knuth 的错误引用)之类的东西来丢弃与性能相关的问题是 SO 的一场瘟疫。
    • -1 优化在现实(专业)世界中很重要,在现实世界中,事情通常规模很大。不要无缘无故一味diss优化
    • 过早的优化是愚蠢的。它使代码几乎总是更难维护,有时甚至使其性能更差。我不是说是这样,但可能是这样。
    • 这里没有意义。废话。这里的优化当然很重要。
    【解决方案4】:

    您可以使用 os.walk 并且仍然使用 glob 样式匹配。

    for root, dirs, files in os.walk(DIRECTORY):
        for file in files:
            if glob.fnmatch.fnmatch(file, PATTERN):
                print file
    

    不确定速度,但显然由于 os.walk 是递归,它们会做不同的事情。

    【讨论】:

      猜你喜欢
      • 2011-02-15
      • 2010-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-19
      • 1970-01-01
      • 2014-05-16
      相关资源
      最近更新 更多