32

我需要浏览一个包含大约一万个文件的文件夹。我的旧 vbscript 处理这个速度很慢。从那时起我开始使用 Ruby 和 Python,我在这三种脚本语言之间做了一个基准测试,看看哪种语言最适合这项工作。

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

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

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

thumbs.db 的测试只是为了测试,实际上还有更多的测试要做。

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

#python2.7.0
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)

if __name__ == '__main__':
  import timeit
  path = '//server/share/folder/'
  print(timeit.timeit('recurse("'+path+'")', setup="from __main__ import recurse", number=1))
'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:5 P:107,后一种情况是 R:4.5 P: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
4

2 回答 2

9

的 Ruby 实现Dir是在 C 中(文件dir.c,根据本文档)。但是,Python 等效项是在 Python中实现的。

Python 的性能不如 C 并不奇怪,但是 Python 中使用的方法提供了更多的灵活性 - 例如,您可以在遍历目录层次结构时跳过名为 eg 的整个子树'.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.
于 2012-10-30T11:45:49.783 回答
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 个文件。

我使用了以下红宝石脚本:

#!/usr/bin/env ruby
require 'benchmark'

def recursive(path, bench)
  bench.report(path) do
    Dir["#{path}/**/**"]
  end
end

path = 'files'
Benchmark.bm {|bench| recursive(path, bench)}

我得到以下结果:

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

我使用 os.walk 使用以下 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 上运行可能也会很有趣。

于 2012-10-31T06:59:41.290 回答