我需要浏览一个包含大约一万个文件的文件夹。我的旧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
答案 0 :(得分:8)
Dir
的Ruby实现在C(文件dir.c
中,根据this documentation)。但是,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.
答案 1 :(得分: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脚本:
#!/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
所以,看起来红宝石仍然表现得更好。看看这个在网络共享上的文件集上是如何执行的,这很有意思。
看到这个脚本在python3和jython上运行,甚至可能还有pypy也可能会很有趣。