基准测试:python是否有更快的方式遍历网络文件夹?

2024-05-13 23:36:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要浏览一个大约有一万个文件的文件夹。我的旧vbscript在处理这个问题时非常慢。因为我从那时起就开始使用Ruby和Python,所以我在这三种脚本语言之间做了一个基准测试,看看哪种语言最适合这项工作。在

下面对共享网络上4500个文件子集的测试结果如下

Python: 106 seconds
Ruby: 5 seconds
Vbscript: 124 seconds

Vbscript速度最慢并不奇怪,但我无法解释Ruby和Python之间的区别。我的Python测试不是最优的吗?在Python中有没有更快的方法来实现这一点?在

测试拇指分贝只是为了测试,实际上还有更多的测试要做。在

我需要一些东西来检查路径上的每一个文件,并且不会产生太多的输出,以免干扰计时。每次运行的结果都有点不同,但差别不大。在

^{pr2}$
'vbscript5.7
set oFso = CreateObject("Scripting.FileSystemObject")
const path = "\\server\share\folder"
start = Timer
myLCfilename="thumbs.db"

sub recurse(folder)
  for each file in folder.Files
    if lCase(file.name) = myLCfilename then
      wscript.echo file
    end if
  next
  for each subfolder in folder.SubFolders
    call Recurse(subfolder)
  next
end Sub

set folder = oFso.getFolder(path)
recurse(folder)
wscript.echo Timer-start
#ruby1.9.3
require 'benchmark'

def recursive(path, bench)
  bench.report(path) do
    Dir["#{path}/**/**"].each{|file| puts file if File.basename(file).downcase == "thumbs.db"}
  end
end

path = '//server/share/folder/'
Benchmark.bm {|bench| recursive(path, bench)}

编辑:由于我怀疑打印造成了延迟,我测试了脚本,打印了所有4500个文件,也没有打印任何文件,但差别仍然存在,第一种情况下的R:5p:107,后一种情况下的R:4.5p:107

EDIT2:基于这里的答案和注释,Python版本在某些情况下可以通过跳过文件夹运行得更快

import os

def recurse(path):
  for (path, dirs, files) in os.walk(path):
    for file in files:
      if file.lower() == "thumbs.db":
        print (path+'/'+file)

def recurse2(path):
    for (path, dirs, files) in os.walk(path):
        for dir in dirs:
            if dir in ('comics'):
                dirs.remove(dir)
        for file in files:
            if file.lower() == "thumbs.db":
                print (path+'/'+file)


if __name__ == '__main__':
  import timeit
  path = 'f:/'
  print(timeit.timeit('recurse("'+path+'")', setup="from __main__ import recurse", number=1)) 
#6.20102692
  print(timeit.timeit('recurse2("'+path+'")', setup="from __main__ import recurse2", number=1)) 
#2.73848228
#ruby 5.7

Tags: 文件pathinimportfordbiffolder
2条回答

我在本地设置目录结构:

for i in $(seq 1 4500); do
    if [[ $i -lt 100 ]]; then
        dir="$(for j in $(seq 1 $i); do echo -n $i/;done)"
        mkdir -p "$dir"
        touch ${dir}$i
    else
        touch $i
    fi
done

这将创建99个文件,路径深度为1-99级,4401个文件位于目录结构的根目录中。在

我使用了以下ruby脚本:

^{pr2}$

我得到了以下结果:

           user     system      total        real
    files/  0.030000   0.090000   0.120000 (  0.108562)

我使用下面的python脚本手术室步行公司名称:

#!/usr/bin/env python

import os
import timeit

def path_recurse(path):
    for (path, dirs, files) in os.walk(path):
      for folder in dirs:
          yield '{}/{}'.format(path, folder)
      for filename in files:
          yield '{}/{}'.format(path, filename)

if __name__ == '__main__':
    path = 'files'
    print(timeit.timeit('[i for i in path_recurse("'+path+'")]', setup="from __main__ import path_recurse", number=1))

我得到了以下结果:

    0.250478029251

所以,看起来ruby的表现仍然更好。看看这个在你的网络共享文件集上的表现会很有趣。在

看到这个脚本在python3、jython甚至pypy上运行也很有趣。在

Dir的Ruby实现在C语言中(根据this documentation,文件dir.c)。但是,Python的等价物实现了in Python。在

Python的性能不如C并不奇怪,但Python中使用的方法提供了更多的灵活性——例如,在遍历目录层次结构时,可以跳过名为'.svn''.git''.hg'的子树。在

大多数时候,Python实现已经足够快了。在

更新:跳过文件/子目录根本不会影响遍历速率,但处理目录树所需的总时间肯定会减少,因为您可以避免遍历主树中潜在的大型子树。节省的时间当然与你跳过多少成正比。在您的例子中,它看起来像是图像的文件夹,您不太可能节省很多时间(除非图像处于修订控制之下,跳过修订控制系统拥有的子树可能会有一些影响)。在

其他更新:跳过文件夹是通过更改dirs值来完成的:

for root, dirs, files in os.walk(path):
    for skip in ('.hg', '.git', '.svn', '.bzr'):
        if skip in dirs:
            dirs.remove(skip)
        # Now process other stuff at this level, i.e.
        # in directory "root". The skipped folders
        # won't be recursed into.

相关问题 更多 >